Range
In the prelude: every iyi program has it, with no import.
The compiler expands a range literal to Range.new(from, to, exclusive) (literal_expander.cr) and predefines the type to refer to it; with no methods, (1..10).each was refused with "wrong number of arguments for 'Range(B, E).new'", a constructor nobody wrote. A range here counts up by one and stops: no Enumerable, no step, no reverse iteration.
Range(B, E)struct
struct Range(B, E)
# A range is a value, so two written the same way are the same range:
# `Object#==` is identity, and `(1..3) == (1..3)` was false. `1..3` and
# `1...3` differ, and that is the flag's whole job.
def ==(other : self) : Bool
# `when 1..5` is `(1..5) === x`: inclusion. `==` answered, and no arm matched.
def ===(value) : Bool
def begin : B
# The inclusive walk stops *at* the end rather than stepping past it: with
# `value <= @end` the last step left the type on the checked `+`, so
# `(2147483645..2147483647).each` panicked with "arithmetic overflow" at
# the value it was asked to yield last.
def each(& : (B -> Nil)) : Nil
def end : E
# `1...10` excludes its end, `1..10` includes it.
def exclusive? : Bool
# And hashing follows equality, or equal ranges would land in two slots.
def hash : Int32
# The three a range is written for: a value per position, the positions
# that answer, and the total.
def map(& : (B -> U)) : Array(U) forall U
def new(begin __arg0 : B, end __arg1 : E, exclusive : Bool)
def select(& : (B -> Bool)) : Array(B)
def size : Int32
def sum : B
def to_a : Array(B)
# `1..5` and `1...3`, each end inspected and a nil one left out, as the
# other library writes one; `Object#to_s` printed `Range(Int32, Int32)`.
def to_s : String
end
Ranges — SPEC.md, "0.1.0", item 3.