Because it was just doing string comparisons and not working with the actual types. I.e. given the setup of like:
class A; end
class B < A; end
class C < B; end
The case was expanding to like, assuming we’re using C
again like your first example:
tmp = obj.class.to_s # => "C"
if tmp == "A"
puts 0
elsif tmp == "B"
puts 1
elsif tmp == "C"
puts 2
end
In this case, even if C
is a child of A
and B
, it wasn’t matching, as again its just string comparisons, so it doesn’t match anything until it gets to "C"
, and prints 2
. However when you switched to the actual typed version, the semantics of the resulting if
statement changed to something like:
tmp = obj
if tmp.is_a? A
puts 0
elsif tmp.is_a? B
puts 1
elsif tmp.is_a? C
puts 2
end
Notice ==
is now is_a?
which takes into consideration that C
is a child of A
and B
, which results in a 0
being printed. This is because of crystal/src/class.cr at eb46097440bf20d22eff6c38fc82732927bb193e · crystal-lang/crystal · GitHub, since #===
is what is used for case equality.