Crystal: Trouble assigning value to ivar typed as `MyParentType(T).class`

Created on 11 Dec 2019  路  7Comments  路  Source: crystal-lang/crystal

My goal was to have a class with an instance variable typed to MyParentType(T).class. This works fine when the class is the same as MyParentType but starts to break down once you introduce a parent type, whether that be an abstract parent class, or a module.

Module Approach

https://play.crystal-lang.org/#/r/86j2

module Parent(T)
end

class Foo(T)
  include Parent(T)
end

class Bar(T)
  include Parent(T)
end

class Wrapper(T)
  def initialize(@foo : Parent(T).class); end
end

pp Wrapper.new Foo(Int32)

# Error: instance variable '@foo' of Wrapper(Int32) must be Parent(Int32).class, not Foo(Int32).class

Class Approach

https://play.crystal-lang.org/#/r/86j3

abstract class Parent(T)
end

class Foo(T) < Parent(T)
end

class Bar(T) < Parent(T)
end

class Wrapper(T)
  def initialize(@foo : Parent(T).class); end
end

pp Wrapper.new Foo(Int32)

# Error: instance variable '@foo' of Wrapper(Int32) must be Parent(T)+.class, not Foo(Int32).class

I'm assuming this is a bug related to generics?

bug topicsemantic

Most helpful comment

Oh, actually, it's not a bug. When a class includes a module, the class inherits the module but the metaclass doesn't inherit the module's metaclass. That's why if you define a def self. method in the module it's not callable from an including class.

I still think we should drop extend from the language, and includeshould just add a parent into the class' and metaclass' hierarchy.

I don't think this will be fixed until we make a decision on how to model all of this.

All 7 comments

I'm assuming this is a bug related to generics?

I don't think so, this fails too with a similar error.

I guess we didn't think of that use case...

module Parent
end

class Foo
  include Parent
end

class Bar
  include Parent
end

class Wrapper
  def initialize(@foo : Parent.class); end
end

pp Wrapper.new Foo

Oh, actually, it's not a bug. When a class includes a module, the class inherits the module but the metaclass doesn't inherit the module's metaclass. That's why if you define a def self. method in the module it's not callable from an including class.

I still think we should drop extend from the language, and includeshould just add a parent into the class' and metaclass' hierarchy.

I don't think this will be fixed until we make a decision on how to model all of this.

But for the generic case it is a bug.

@asterite 馃憤, should I create another issue for the module one and keep this one scoped to the class issue?

The module one is not a bug, so I'm not sure...

@asterite Sorry I meant more so to represent the idea of removing extend, or is there an issue already tracking that?

It's just a thought or I wish I have, no concrete plans or design yet so I wouldn't open an issue for it.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

costajob picture costajob  路  3Comments

nabeelomer picture nabeelomer  路  3Comments

asterite picture asterite  路  3Comments

oprypin picture oprypin  路  3Comments

cjgajard picture cjgajard  路  3Comments