Feature #5005

Provide convenient access to original methods

Added by Lazaridis Ilias almost 3 years ago. Updated over 1 year ago.

[ruby-core:37917]
Status:Rejected
Priority:Normal
Assignee:Yukihiro Matsumoto
Category:-
Target version:next minor

Description

The languag allows a class to be "reopened", thus it's behaviour can be redefined:

class String
def any_method
#custom code
end
end

the original method can be called, using this construct:

class String
aliasmethod :originalanymethod, :anymethod
def anymethod(*args)
#custom code
original
any_method(*args)
#custom code
end
end

In order to make this more convenient, the following construct could be provided:

class String
def anymethod(*args)
#custom code
original # call the original String#any
method, passing *args (similar to "super")
#custom code
end
end

"original" would behave similar to "super"

The term "original" can be replaced by any term which describes this concept better.

History

#1 Updated by Nobuyoshi Nakada almost 3 years ago

  • Target version set to Next Major

#2 Updated by Michael Klishin almost 3 years ago

This approach with aliasing seems to be pretty popular because many people do not know that it is possible to define a module with #any_method and include it into a class (in your example, String) and call super in that module method. This feature will open a whole new wave of reinvented OOP wheels. Adding new language features just to work around controversial OOP practices does not sound like a good idea to me personally.

#3 Updated by Ondrej Bilka almost 3 years ago

Michael Klishin wrote:

This approach with aliasing seems to be pretty popular because many people do not know that it is possible to define a module with #any_method and include it into a class (in your example, String) and call super in that module method. This feature will open a whole new wave of reinvented OOP wheels. Adding new language features just to work around controversial OOP practices does not sound like a good idea to me personally.

Could you elaborate what did you mean?
module B
def foo
super+"b"
end
end
class A
def foo
"a"
end
include B
end
puts A.new.foo
returns a which is not what was wanted

#4 Updated by Michael Klishin almost 3 years ago

Ondrej,

When module is included into a class, Ruby adds a new anonymous (in a sense that it will be skipped by Class#superclass calls) class into the inheritance chain: https://gist.github.com/1073599. So it is appending, not prepending. This is useless for core classes like String, however, most cases of blatant monkey-patching that I see look more like this: https://gist.github.com/1073605. In that case, aliased methods is a reinvented wheel.

#5 Updated by Yukihiro Matsumoto almost 3 years ago

The idea to address the issue is the "prepend" feature planned for Ruby 2.0.

class Original
def any_method
...
end
end

module Modifier
def anymethod
#custom code
super # call the original any
method, passing *args
#custom code
end
end

reopen class

class Original
prepend Modifier
end

The prepend method pushes a module in front of a class so that super calls the original method.

matz.

#6 Updated by Ondrej Bilka almost 3 years ago

One of answers is use AOP like aquarium(But I didn't tried it so I dont
know if it isn't overkill).
Currently best solution is use unbound method which is not much intuitive
From perspective that easiest solution should be too wrong we could
introduce wrapmethod. It avoids problems when aliasmethod break
alias_method of previous guy.

class Module
def wrapmethod(foo)
i=instance
method(foo)
define_method(foo){|a|
yield(i.bind(self),
a)
}
end
end

class A
def foo
1
end
wrap_method(:foo){|prev|
prev.()+1
}
end
puts A.new.foo

On Sat, Jul 09, 2011 at 11:27:46PM +0900, Yukihiro Matsumoto wrote:

Issue #5005 has been updated by Yukihiro Matsumoto.

The idea to address the issue is the "prepend" feature planned for Ruby 2.0.

class Original
def any_method
...
end
end

module Modifier
def anymethod
#custom code
super # call the original any
method, passing *args
#custom code
end
end

reopen class

class Original
prepend Modifier
end

The prepend method pushes a module in front of a class so that super calls the original method.

matz.


Feature #5005: Provide convenient access to original methods
http://redmine.ruby-lang.org/issues/5005

Author: Lazaridis Ilias
Status: Open
Priority: Normal
Assignee:
Category: core
Target version: 2.0

The languag allows a class to be "reopened", thus it's behaviour can be redefined:

class String
def any_method
#custom code
end
end

the original method can be called, using this construct:

class String
aliasmethod :originalanymethod, :anymethod
def anymethod(*args)
#custom code
original
any_method(*args)
#custom code
end
end

In order to make this more convenient, the following construct could be provided:

class String
def anymethod(*args)
#custom code
original # call the original String#any
method, passing *args (similar to "super")
#custom code
end
end

"original" would behave similar to "super"

The term "original" can be replaced by any term which describes this concept better.

http://redmine.ruby-lang.org

--

Your EMAIL is now being delivered by the USPS.

#7 Updated by Lazaridis Ilias almost 3 years ago

=begin

I've notice a related issue, #3688, which suggests the introduction of "redef". This, in combination of "original", would be an extension more native to the language - avoiding this way to (ab)use the general construct "super(class-method)", which has a very specific meaning in standard OO.

"redef" would allow to keep track of the redefined method.

Another way would be, that the usual "def" detects that a redefinition happens, thus is keeps automatically a copy of the original method, which "original" accesses then.

This way, "original" would take care about multiple redefinitions, calling always the right one, without any effort for the user.

=end

#8 Updated by Lazaridis Ilias almost 3 years ago

Lazaridis Ilias wrote:

The languag allows a class to be "reopened", thus it's behaviour can be redefined:
[...]
"original" would behave similar to "super"

The term "original" can be replaced by any term which describes this concept better.

Just realized that "previous" would be a more concise term.

  • super : the super(class) method, standard OO terminology
  • original : the original, the first, the basic version of the method (e.g. C-level one)
  • previous : the previous version of this method, the overridden one (either the original one, or an already redefined)

#9 Updated by Martin Dürst almost 3 years ago

Just some general thoughts on making metaprogramming easier:

Using metaprogramming in Ruby is on average somewhat more lengthy/clumsy than straightforward/plain (i.e. non-meta) programming. I have been thinking about why that may be. It could just be that most of the attention has been on plain programming, and metaprogramming hasn't been polished as much yet as plain programming. But over time, I got the impression that to some extent, leaving metaprogramming to be somewhat more clumsy may have been intentional.

Metaprogramming is a very powerful tool, and therefore programmers should think hard about how to use it well. If it gets too easy and straightforward, then it's going to be overused. I agree that method patching as in this feature request and in #3688 is very frequent. But it is often a quick patch to an underlying problem that might benefit from further thought. If we make it easier with 'redef' or 'original' or some other keyword or syntax, then it will easily become even more over/abused. This may also apply to other cases of metaprogramming.

#10 Updated by Yui NARUSE over 2 years ago

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

#11 Updated by Yui NARUSE over 2 years ago

  • Project changed from CommonRuby to ruby-trunk

#12 Updated by Yusuke Endoh about 2 years ago

  • Status changed from Open to Assigned
  • Assignee set to Yukihiro Matsumoto

#13 Updated by Yusuke Endoh over 1 year ago

  • Target version set to next minor

#14 Updated by Nobuyoshi Nakada over 1 year ago

  • Status changed from Assigned to Rejected

Use Module#prepend and super.

Also available in: Atom PDF