crystal-lang / crystal

The Crystal Programming Language
https://crystal-lang.org
Apache License 2.0
19.33k stars 1.61k forks source link

[RFC] Metaclasses of abstract types should not themselves be abstract #9959

Open HertzDevil opened 3 years ago

HertzDevil commented 3 years ago

Follow-up to https://github.com/crystal-lang/crystal/issues/5956#issuecomment-731856760.

There is no such thing as an abstract base metaclass in Crystal; as long as you can name a type, that type is already an instance of its metaclass, even if the user never explicitly instantiates the type object. Besides, code like this is perfectly legal:

abstract class Foo
  abstract def f
  class_property x = 1
end

Foo.x += 1 # => 2

Thus it is erroneous to declare Foo.class itself as an abstract type.

The differences become apparent when virtual types involving metaclasses are resolved into concrete types. Suppose we have

abstract class Base
end

class Derived < Base
  def self.foo
  end
end

(true ? Base : Derived).foo

When Base.class is abstract,

When Base.class is not abstract,

Now also consider the example from #3835:

abstract class Foo
end

a = [Foo] of Foo.class
a[0].new

Suppose Foo.class#new is not defined (the compiler detects the Foo.new errors through a different mechanism). The code would still compile, since Foo.class is abstract and the concrete types of Foo.class+ must all define #new. But if a[0] is typed to be Foo+.class, then due to our supposition the code would fail to compile, because the last line requires a definition of Foo.class#new.

This will be a breaking change but I can't think of a scenario where the current behaviour is desirable.

asterite commented 3 years ago

I think you are right but ai can't understand what is a proposal and what is currently working the way you say. Could you clarify what are the proposed changes, and how, if you want to generically call new on a bunch of types that inherit from an abstract type, make that work?