How to add second constructor to class whose superclass initializes all instance variables in a macro literal in the constructor

I have a superclass like so,

abstract class Klass
  def initialize
    {% for ivar in @type.instance_variables %}
      @{{ivar.name}} = {{ivar.type.id}}.new
    {% end %}
  end
end

and when I subclass it without specifying a constructor, it works as expected.

class OKSubKlass < Klass
  property prop : Hash(String, String)
end

However, if I add any constructor at all, I get an error because the superclass’s constructor overloads are no longer detected.

class NotOK < Klass
  property prop : Array(Int)
  def initialize(arr)
    @prop = arr
  end
end
# gives this error: 
# wrong number of arguments for 'NotOK.new' (given 0, expected 1)
# Overloads are:
#  - NotOK.new(arr)

If I define the overload and leave it with just super, it still doesn’t compile, saying @prop needs to be nillable.

class StillNotOK < Klass
  property prop : Tuple(String)
  def initialize
    super
  end
  def initialize(val)
    @prop = val
  end
end

Is there a workaround or way to write this or have I simply encountered something you can’t do in crystal?

I think the last example should work. NotOK won’t compile because adding one constructor hides all the parent classes overloads.

I didn’t have time to take a look at this but it’s probably a bug. There’s a bug related to initializing instance vars with that kind of macro (using instance vars of a type). For now I suggest to avoid that.

Meta – it would be cool to have custom emojis on this forum. A one with Ary’s avatar on it would be so much appropriate for this kind of messages :laughing:

Thanks @asterite, should I open an issue for this then?

Yes, please, unless you can find an existing one for this (I didn’t try that yet)