The Crystal Programming Language Forum

Strange things with Class

Hello, I need a variable of type Class and I found the following behaviors:

I can do this:

puts typeof(Bool | Int32 | Int64 | String)
# => (Bool | Int32 | Int64 | String).class

but not this (why?):

c : typeof(Bool | Int32 | Int64 | String) = Bool
# => Error: type must be (Bool | Int32 | Int64 | String).class, not Bool.class

also I can do this:

c : Bool.class | Int32.class | Int64.class | String.class = Bool
puts typeof(c) # => Class (!!!)
puts c # => Bool

Look at this! typeof(c) is Class (so, union of several Classes is aggregated to the Class and it works)!

but I can’t do this:

c : Class = Bool
puts c
# => Error: can't use Object as the type of a variable yet, use a more specific type

Can’t use Class as type directly - but look at example above, when union is aggregated to the Class

Is this OK?

I’m really wondering what’s your use case :thinking:

We have dozens of “Entity” classes and we need to store some internal metadata about relations etc., so we need an attribute (instance variable) with type “Class” to point to our relation class.

It’s not about use case - it’s just an instance variable (or simple variable) that stores Class - simple.
And that work with Classes is a little strange as you can see.

The type of a union of classes is different than the union of classes.

So in:

c : typeof(Bool | Int32 | Int64 | String)

the only thing you can assign is Bool | Int32 | Int64 | String, while in:

c : Bool.class | Int32.class | Int64.class | String.class

you can assign any of Bool, Int32, etc.

I think in the past both types were equal or resolved to a same time and I think we changed that because it was unsound (I can’t remember why).

Then you get Class for asking the type of a class (like Bool.class). There’s a PR to change that so that typeof(Bool.class) gives you Bool:Class:Class but we are not sure it’s the right thing to do: https://github.com/crystal-lang/crystal/pull/7255

In your case you probably need to use the Bool.class | Int32.class approach, but maybe showing some more code for what you want/need might be better.