Feature #7250
openA mechanism to include at once both instance-level and class-level methods from a module
Description
=begin
I have simply commented first on #7240, but i feel i need to start a ticket in order to not post off topic.
This seems to be a big feature request, so i didn't feel confident to suggest, but when i read in #7240 that (({Module#included})) hook can become even more hooked, i've decided to express myself.
=== Proposal
In my opinion, the most common use case for the "(({included}))" hook in modules is adding class methods. However, to me this looks hackish and hard to follow. I would have preferred if there was a way to define both instance-level and class-level behavior in a module and include both at once. Here is an API i would suggest:
module M
def foo
'Foo'
end
def base.bar # here a fictional private method Module#base is called
'Bar'
end
end
class C
include M
end
a = C.new
a.foo # => 'Foo'
C.bar # => 'Bar'
This means that a module would need to store 2 method tables, one as usual, and a second one defined as singleton methods on some object returned by some private method, called for example (({Module#base})). Since ordinary objects have no method table, classes have one method table, why not to allow modules to have 2 method tables?
=== Relevant considerations
-
Talking about method tables, maybe if objects were allowed to have one, there would be no need for meta-classes? (Then classes would have 2 method tables, modules would have 3, and in fact methods and method tables could be regarded as kinds of attributes.) It looks to me like meta-class is simply there to make up for the fact that objects are not allowed to keep their own methods.
-
Allowing modules to have more method tables than classes may look like breaking the inheritance (({Class < Module})), but to me this inheritance does not look like a good idea anyway. For example, a module can be included, but a class cannot. To me, class looks like an object factory, but a module like a container of parts that can be unpacked and mounted onto a class.
=== Irrelevant considerations
I think that from the point of view of English, the method name "(({included}))" is not consistent with the method name "(({extended}))" (the module is included, but the base is extended).
I would have preferred if the word "(({extend}))" was used instead of "(({include}))" when "including" one module into another, as this operation seems somewhat different from including a module into a class. I understand that it makes no sense to discuss this now, when (({extend})) is already has its fixed meaning.
=end