Crystal: Class methods can't be included from modules

Created on 27 Jun 2019  路  10Comments  路  Source: crystal-lang/crystal

For some reason class methods can't be included from modules:

module Bar
  def self.bar
  end
end

class Foo
  include Bar
end

Foo.bar # undefined method 'bar' for Foo.class

Is this the desired behaviour? If so, why isn't this allowed?

Most helpful comment

I'm in favor of removing extend and letting include copy class methods and variables. I don't think Crystal needs to be exactly like Ruby, especially when it comes to the not-so-great parts of Ruby.

All 10 comments

This behaviour is copied without modification (as far as I know) from Ruby. I'm not certain it is optimal though - I wouldn't really mind having module behave like Rails concerns (which is one way to handle it).

But to actually answer your question, you can create a module like

module Bar
  def bar
  end
end

and then use the extend keyword to add the methods as class methods.

EDIT: Fix typo, that @malte-v pointed out

If you want to use extend, the module methods need to be instance methods. Class methods aren't copied over by extend.

This works exactly like in Ruby though I always wondered whether only include should exist in the language (though one use case of extend in the standard library is ENV extends Enumerable, but that could always be something like ENV = Env.new and making Env include Enumerable).

It would also simplify the language a bit.

I'm in favor of removing extend and letting include copy class methods and variables. I don't think Crystal needs to be exactly like Ruby, especially when it comes to the not-so-great parts of Ruby.

including modules inside classes to now shadow-act as a class method (when it's really a method from a module) is confusing, concealing, less explicit, and probably more prone to bugs

the compiler is doing us a favor by showing this error

@girng Can you clarify why this would be confusing? Modules can also have class methods and variables.

One major thing to consider when removing extend: What about extend self? Maybe add a new namespace keyword?

@malte-v Not sure, but off the top of my head, if a developer is looking for included methods in a class, they are going to be looking for methods under a class, not a module

extend self is just adding self. to each method. We have a similar thing with private and protected: you have to add those to each method. So living without extend self isn't a really big deal, I think.

I'm going to close this because this is working as expected, at least with the current semantics. Maybe in the future we'll change them but it's independent of this issue being open.

Was this page helpful?
0 / 5 - 0 ratings