Feature #1102

Prepend Module

Added by Thomas Sawyer over 6 years ago. Updated about 3 years ago.

[ruby-core:21822]
Status:Closed
Priority:Normal
Assignee:Nobuyoshi Nakada

Description

=begin
Currently when a module is included into a classes, it is appended to the class hierarchy (ie. the method lookup order). This of course makes sense, but there are times when it would be useful to prepend the module. For example:

class C
def x; "x"; end
end

module M
def x; '[' + super + ']'; end
end

class C
prepend M
end

C.new.x #=> "[x]"

One big advantage of this is being able to override methods in a safer way, rather than using alias or tricks like alias_method_chain.
=end


Related issues

Related to Ruby trunk - Feature #6452: Allow extend to override class methods Assigned 05/19/2012

Associated revisions

Revision 36234
Added by Nobuyoshi Nakada about 3 years ago

Module#prepend

  • class.c (rb_prepend_module): prepend module into another module.
  • eval.c (rb_mod_prepend): new method Module#prepend. [Feature #1102]

Revision 36234
Added by Nobuyoshi Nakada about 3 years ago

Module#prepend

  • class.c (rb_prepend_module): prepend module into another module.
  • eval.c (rb_mod_prepend): new method Module#prepend. [Feature #1102]

History

#1 Updated by Thomas Sawyer over 6 years ago

=begin

On Feb 7, 10:42 pm, Roger Pack rogerdp...@gmail.com wrote:

Currently when a module is included into a classes, it is appended to the class hierarchy (ie. > the method lookup order). This of course makes sense, but there are times when it would be > useful to prepend the module. For example:

I suppose one [not too useful] hack at it could be something like

class Class
  def insert_module_at_top mod
    previous_ancestors = self.ancestors.select{|a| a.class == Module}
    include mod
    previous_ancestors.each{|a| include a.dup}
  end
end

#again we have to start with a module.

module Original
  def x; '[' + super + ']'; end
end

class A
 include Original
end

modulePrepend
 def x; "x"; end
end
A.insert_module_at_topPrepend
puts A.new.x
=> [x]

Perhaps what we're saying here is we wish we could "grab" methods from
classes, to be able to manipulate the hierarchy better?  This is
possible with RubyParser, since you can basically get back to the
source of the method and thus copy it around, but not afaik with 1.9

Well, that's not really the issue here. The need is to wrap
previously defined instance methods. If every method were defined in a
module (something I have suggested in the past actually) then it would
not be needed.

The utility comes from doing AOP-esque coding. Consider modules that
can initialize values.

class X
end

module P
attr :p
def initialize
@p = []
super
end
end

class X
prepend P
end

X.new.p => []

T.

=end

#2 Updated by Marc-Andre Lafortune almost 6 years ago

  • Assignee set to Yukihiro Matsumoto

=begin

=end

#3 Updated by Roger Pack over 5 years ago

=begin
+1 for Module#prepend
=end

#4 Updated by Michael Fellinger over 5 years ago

=begin
+1 for Module#prepend
=end

#5 Updated by Yusuke Endoh over 5 years ago

  • Target version changed from 2.0.0 to Next Major

=begin
Hi,

This ticket was also discussed in the thread from .

Module#prepend may be very significant feature not only to implementation
but also to Ruby's OO model itself.
Don't consider it just convenient method like Array's and String's.

So, in my opinion, this feature should not be included in 1.9.x.
We should discuss it towards 2.0.

Even if it will be included in 1.9.x, we need more discussion.
Just seeing clean example, you'll find it cool. But in fact, we must
also discuss many dirty things:

  • edge semantics

    • prepend into embedded class
    • prepend into singleton class
    • collaboration with reflection
    • collaboration with future expansion (e.g., classbox)
    • etc.
  • implementation

    • robustness
    • binary compatibility
    • expandability
    • maintainability
    • performance

I think it is difficult to discuss them without material. So, please
write a patch first if you really want.

--
Yusuke Endoh mame@tsg.ne.jp
=end

#6 Updated by Yusuke Endoh over 5 years ago

  • Status changed from Open to Feedback

=begin

=end

#7 Updated by Yui NARUSE almost 4 years ago

  • Project changed from Ruby trunk to CommonRuby
  • Category deleted (core)
  • Target version deleted (Next Major)

#8 Updated by Yui NARUSE almost 4 years ago

  • Project changed from CommonRuby to Ruby trunk

#9 Updated by Yusuke Endoh over 3 years ago

This feature is listed as matz's "must-have."
Are there any volunteers to be a facilitator, to create a prototype,
and/or, to study the semantics and implementation?
Sorry I'll have no time, and completely forgot the discussion.

   ___
  _|*|_
  (`_`)
  m9

I WANT YOU

Yusuke Endoh mame@tsg.ne.jp

#10 Updated by Koichi Sasada over 3 years ago

  • Assignee changed from Yukihiro Matsumoto to Koichi Sasada
  • Target version set to 2.0.0

#11 Updated by Koichi Sasada about 3 years ago

  • Assignee changed from Koichi Sasada to Nobuyoshi Nakada

Nobu will commit it.

#12 Updated by Nobuyoshi Nakada about 3 years ago

  • Status changed from Feedback to Closed
  • % Done changed from 0 to 100

This issue was solved with changeset r36234.
Thomas, thank you for reporting this issue.
Your contribution to Ruby is greatly appreciated.
May Ruby be with you.


Module#prepend

  • class.c (rb_prepend_module): prepend module into another module.
  • eval.c (rb_mod_prepend): new method Module#prepend. [Feature #1102]

Also available in: Atom PDF