The Crystal Programming Language Forum

Type confusion

I am working on a small library and I’m trying to do something similar to this where I have this one super class that a bunch of other classes are going to inherit from

abstract class Animal
  abstract def speak(sound : String)
end

class Cat < Animal
  def speak(sound : String)
    sound
  end
end

animals : Array(Animal) = [Cat.new]

I would expect this to work because Cat inherits from Animal and therefore is an Animal (?) but for some reason this is not allowed? :thinking:

Error ouput

Showing last frame. Use --error-trace for full trace.

error in line 11
Error: type must be Array(Animal), not Array(Cat)

Top question asked.

You have to do [Cat.new] of Animal

Otherwise the compiler infers the array to be of Cat, and that’s not compatible con with an array of Animal.

Search for covariance and contravariance in the forums or the Github issues, you’ll find plenty of examples of why this isn’t allowed.

5 Likes

There are a couple of alternatives to what Asterite suggested, for example

animals = Array(Animal).new
animals << Cat.new

or

animals = Array(Animal){Cat.new}

Which fits better for your particular situation depends on how the rest of your code looks like.

3 Likes

Thank you @asterite and @yxhuvud for your replies, they were very helpful! :slight_smile:

I’ll have a look at covariance and contravariance as mentioned to get a better understanding of this.