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?
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.
Most helpful comment
I'm in favor of removing
extend
and lettinginclude
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.