Type autocasting¶
Crystal transparently casts elements of certain types when there is no ambiguity.
Number autocasting¶
Values of a numeric type autocast to a larger one if no precision is lost:
def foo(x : Int32) : Int32
x
end
def bar(x : Float32) : Float32
x
end
def bar64(x : Float64) : Float64
x
end
foo 0xFFFF_u16 # OK, an UInt16 always fit an Int32
foo 0xFFFF_u64 # OK, this particular Int64 fit in an Int32
bar(foo 1) # Fails, casting an Int32 to a Float32 might lose precision
bar64(bar 1) # OK, a Float32 can be autocasted to a Float64
Number literals are always casted when the actual value of the literal fits the target type, despite of its type.
Expressions are casted (like in the last example above), unless the flag no_number_autocast
is passed to the compiler (see Compiler features).
If there is ambiguity, for instance, because there is more than one option, the compiler throws an error:
def foo(x : Int64)
x
end
def foo(x : Int128)
x
end
bar = 1_i32
foo bar # Error: ambiguous call, implicit cast of Int32 matches all of Int64, Int128
Autocasting at the moment works only in two scenarios: at function calls, as shown so far, and at class/instance variable initialization. The following example shows an example of two situations for an instance variable: casting at initialization works, but casting at an assignment doesn't:
class Foo
@x : Int64 = 10 # OK, 10 fits in an Int64
def set_x(y)
@x = y
end
end
Foo.new.set_x 1 # Error: "at line 5: instance variable '@x' of Foo must be Int64, not Int32"
Symbol autocasting¶
Symbols are autocasted as enum members, therefore enabling to write them more succinctly:
enum TwoValues
A
B
end
def foo(v : TwoValues)
case v
in TwoValues::A
p "A"
in TwoValues::B
p "B"
end
end
foo :a # autocasted to TwoValues::A