Type must be (Int64 | Int8), not Int32

Following code:

x : Int64 | Int8 = 0

Yields error:

 type must be (Int64 | Int8), not Int32

What’s happening?

You are giving x a type restriction of Int64 | Int8, but are assigning a value that is of type Int32.

Crystal docs say -128…127 are valid Int8.

https://crystal-lang.org/reference/syntax_and_semantics/literals/integers.html

Now what?

Yes but in this context 0 has a type of Int32 by default. You would have to tell the compiler that you want 0 to be of type Int8, i.e. 0_i8.

If no suffix is present, the literal's type is the lowest between Int32, Int64 and UInt64 in which the number fits. Notice the little example they have in the doc you linked.

Okay yes I remember reading that now.

By my previous statement, reading doesn’t imply learning, in my case. So I must actually TYPE Crystal in order to learn, which I am enjoying btw. :slight_smile:

Thank-you for responding quickly.

I really, really like having types. I learned to love types via SQL. And now I get it in “Ruby”.

No problem. Yes the type system is quite handy :)

Is there a way to see the set of types for a variable? typeof only shows me what the type of the variable’s current value is.

Maybe my question is not so good. First, I see there are functions for objects like tuple that give the set of types. If I always declare my types, which I plan to, I should be able to find the variable’s declaration and know from that.

typeof is kinda smart in that it shows you the types a variable have a chance of being. In your case x is only ever assigned to 0_i8 so the type of x is always going to be Int8. However if you do like:

val = "Foo"

if val == "bar"
  val = 123
end

typeof(val) # => (String | Int32)

In this case val is initialized as a string, but is possible it could be an Int32 as well. typeof(val) reflects that.

Tuple is a bit unique as the types of each element are known at compile time.

Very cool example. I hope to never do such things in my own code. Specifically, have union-type of 2 disparate types, e.g. String, Integer. Obviously Int8, Int32 is less disparate.

My training in relational-theory taught me to avoid NULL at almost any cost. I intend to carry that into Crystal. Time shall tell.

1 Like

Note that x : Int64 = 0 or x : Int8 = 0 works thanks to auto-casting, but x : Int64 | Int8 = 0 does not.

What do you mean by “works”? x : Int64 = 0 does-not look “auto-casted” to me; it looks explicit.

I think I get what you’re saying.

Absent a union-type, Crystal will assign the right type based on the singular type given.

Oh… okay. Auto-casting of the LITERAL value, 0. Gotcha. Cool. Yes, lots to learn, lots of nuance.

That it compiles and does what you would expect :slight_smile:

0 as an expression is of type Int32. But the compiler will notice on some cases that literals are used as values of other types and will interpret them different. More about it here.