Finding one's way with 'super' in define_method/alias_emthod

Hi all!
This is my first post here, so please don’t yell at me too harshly :slight_smile:
I have a little problem with ‘super’ keyword when it is used in
define_method/alias_method. First, a little example:

class C
def greetings
p “Hello, #{caller.first}”
end
def curses
p “Damn you, #{caller.first}”
end
end

class D < C
def greetings
super
end
define_method :curses, instance_method(:greetings)
end

[3] pry(main)> D.new.greetings
“Hello, (pry):11:in greetings'" => "Hello, (pry):11:ingreetings’”
[4] pry(main)> D.new.curses
“Hello, (pry):11:in greetings'" => "Hello, (pry):11:ingreetings’”

So, as you can see ‘super’ is bound, perhaps a little unexpectedly, to
a method instance rather than to its call site. You can see it clearly
when inspecting the caller - in both cases it is ‘greetings’. While
this may seem logical and sound, it is quite troubling when you try to
make a wrapper method around user-defined method doing metaprogramming
tricks. For example, I am trying to implement the chain pattern like
this:

def chain
new_method_name = “__#{@__chain_method}”
chained_method = @__chain_method

    #....

    alias_method new_method_name, chained_method
    private new_method_name
    remove_method chained_method

    define_method(chained_method) do |*args|
      send(new_method_name, *args) do |*yielded_args|
        #...
      end
    end unless method_defined? chained_method

    #...

end

In short, when a new method of given name is defined I alias it to
some other name (__old_name) and then I define another method
replacing user-defined method. In pseudo-code

def execute
#…
end

ends up as

def __execute; end;
def execute; … send(__execute) …; end;

Works like a charm, except when original method contains super - it is
supposed to call superclass’ __execute, but it calls superclass
execute instead and all this ends up with stack overflow (intended
callchain should be: execute -> __execute(child) -->
__execute(parent), but is: execute -> __execute(child) -> execute ->
__execute(child)).
Do you know any workaround? How can I overcome this problem and let
super be bound correctly if used from aliased method? Thanks in
advance for your opinions.

On Mon, Mar 18, 2013 at 5:50 PM, Marcin Rzeźnicki
[email protected] wrote:

Hi all!
This is my first post here, so please don’t yell at me too harshly :slight_smile:

Welcome to the wonderful world of Ruby!

end
=> “Hello, (pry):11:in greetings'" [4] pry(main)> D.new.curses "Hello, (pry):11:in greetings’”
=> “Hello, (pry):11:in `greetings’”

So, as you can see ‘super’ is bound, perhaps a little unexpectedly, to
a method instance rather than to its call site.

Hmm, I’d still say it’s the call site since the call site sits in
method D#greeting even though the method is also known as D#curse.

You can see it clearly
when inspecting the caller - in both cases it is ‘greetings’. While
this may seem logical and sound, it is quite troubling when you try to
make a wrapper method around user-defined method doing metaprogramming
tricks.

Do you know any workaround? How can I overcome this problem and let
super be bound correctly if used from aliased method? Thanks in
advance for your opinions.

I am not sure what you expect should be called “bound correctly”.
Basically what you did is you said D#curse should be D#greeting
(either via define_method as shown above or alias). That means, D’s
method #curse behaves like D’s #greeting and hence ultimately invokes
C#greeting and not C#curse.

Btw, somehow your chain example seems incomplete: is #chain a method
defined in Module? What about method names? I would have expected
the chained method name to be given as argument.

I once coded something together for wrapping methods - you may find it
in the archives. I am not sure though that I still have the code
elsewhere… I only found this one:
https://gist.github.com/rklemme/3002732 but that’s not the one I mean.

Kind regards

robert

Robert K. wrote in post #1102151:

On Mon, Mar 18, 2013 at 5:50 PM, Marcin Rzeźnicki
[email protected] wrote:

Hi all!
This is my first post here, so please don’t yell at me too harshly :slight_smile:

Welcome to the wonderful world of Ruby!

Thank you :slight_smile:

So, as you can see ‘super’ is bound, perhaps a little unexpectedly, to
a method instance rather than to its call site.

Hmm, I’d still say it’s the call site since the call site sits in
method D#greeting even though the method is also known as D#curse.

Yes, maybe I picked wrong terminology in my example. What I meant was
that even though this method object is still the same, it is being
called as something different (I’d say - method instance is simply
reused but that’s an implementation detail for me, so I’d prefer it to
be masked out), so I would expect call frames to represent that.

You can see it clearly
when inspecting the caller - in both cases it is ‘greetings’. While
this may seem logical and sound, it is quite troubling when you try to
make a wrapper method around user-defined method doing metaprogramming
tricks.

Do you know any workaround? How can I overcome this problem and let
super be bound correctly if used from aliased method? Thanks in
advance for your opinions.

I am not sure what you expect should be called “bound correctly”.
Basically what you did is you said D#curse should be D#greeting
(either via define_method as shown above or alias). That means, D’s
method #curse behaves like D’s #greeting and hence ultimately invokes
C#greeting and not C#curse.

When I imagine hypothetical pseudo-code implementation of define_method
I’d rather see: object[:method_name] = method_instance.code, than
object[:method_name] = method_instance :slight_smile:

Btw, somehow your chain example seems incomplete: is #chain a method
defined in Module? What about method names? I would have expected
the chained method name to be given as argument.

Ah yes, I omitted lots of details for brevity, trying to get to the
bottom line, if you will. Basically, chain is called from method_added
hook. When you include the module it installs this hook, adds class
method to specify the name of a “chained” method, listens for
subclassing to get into child class to do the trick again etc., but I
felt that this boilerplate was irrelevant to my problem.

I once coded something together for wrapping methods - you may find it
in the archives. I am not sure though that I still have the code
elsewhere… I only found this one:
https://gist.github.com/rklemme/3002732 but that’s not the one I mean.

I will certainly try to find it. Many thanks. BTW, judging from example
you posted (I have not yet run it, though) it exhibits the same problem
as my implementation - calling super from #_m would call #m in parent
class which could call #_m in child again.


Greetings
Marcin Rzeźnicki

On Mon, Mar 18, 2013 at 8:39 PM, Marcin R. [email protected] wrote:

Robert K. wrote in post #1102151:

On Mon, Mar 18, 2013 at 5:50 PM, Marcin Rzeźnicki

I am not sure what you expect should be called “bound correctly”.
Basically what you did is you said D#curse should be D#greeting
(either via define_method as shown above or alias). That means, D’s
method #curse behaves like D’s #greeting and hence ultimately invokes
C#greeting and not C#curse.

When I imagine hypothetical pseudo-code implementation of define_method
I’d rather see: object[:method_name] = method_instance.code, than
object[:method_name] = method_instance :slight_smile:

Your expectation was clear. But others may have different
expectations. We are discussing to try to find out what might be more
reasonable or what expectations might be shared by more people. :slight_smile:
That’s why I questioned whether the term “correctly” was appropriate
here.

Btw, somehow your chain example seems incomplete: is #chain a method
defined in Module? What about method names? I would have expected
the chained method name to be given as argument.

Ah yes, I omitted lots of details for brevity, trying to get to the
bottom line, if you will. Basically, chain is called from method_added
hook. When you include the module it installs this hook, adds class
method to specify the name of a “chained” method, listens for
subclassing to get into child class to do the trick again etc., but I
felt that this boilerplate was irrelevant to my problem.

Maybe you left out too many details. :slight_smile: It usually helps to provide
a small and above all complete example that others can execute:
http://sscce.org/

I once coded something together for wrapping methods - you may find it
in the archives. I am not sure though that I still have the code
elsewhere… I only found this one:
Wrap all methods with a specific code · GitHub but that’s not the one I mean.

I will certainly try to find it. Many thanks. BTW, judging from example
you posted (I have not yet run it, though) it exhibits the same problem
as my implementation - calling super from #_m would call #m in parent
class which could call #_m in child again.

Yes, super and alias don’t mix well. You could argue that a method’s
behavior would change depending on the name used to invoke it if Ruby
was made to match your expectation. There are two downsides:

  1. Could be viewed as an aesthetic issue: the behavior of code would
    change after the definition of the method.
  2. As a consequence of changed behavior there would be a runtime
    effect: while executing the interpreter would have to have knowledge
    of the name used to invoke a method. Now you could argue that this
    knowledge does actually exist (caller provides it) but it may incur a
    runtime hit - for just a small amount of use cases.

Redefining a super class method also affects what code “super” will
invoke:

irb(main):001:0> class A
irb(main):002:1> def x; p 1 end
irb(main):003:1> end
=> nil
irb(main):004:0> class B < A
irb(main):005:1> def x; p 2; super end
irb(main):006:1> end
=> nil
irb(main):007:0> B.new.x
2
1
=> 1
irb(main):008:0> class A
irb(main):009:1> alias _x x
irb(main):010:1> def x; p 3; _x end
irb(main):011:1> end
=> nil
irb(main):012:0> B.new.x
2
3
1
=> 1
irb(main):013:0> A.new.x
3
1
=> 1

And then there is the issue that you can invoke a method without a
name. What method would super invoke in that case?

irb(main):024:0> m = B.instance_method :x
=> #<UnboundMethod: B#x>
irb(main):025:0> b = B.new
=> #<B:0x88d0f38>
irb(main):026:0> m.bind(b).call
2
3
1
=> 1

With a slightly different experiment you can see that aliasing a
method just creates a second reference to the same code:

irb(main):001:0> class X
irb(main):002:1> def x; caller 0 end
irb(main):003:1> alias y x
irb(main):004:1> end
=> nil

irb(main):006:0> puts X.instance_method(:x).bind(X.new).call
(irb):2:in x' (irb):6:in call’
(irb):6:in irb_binding' /usr/lib/ruby/1.9.1/irb/workspace.rb:80:in eval’

irb(main):007:0> puts X.instance_method(:y).bind(X.new).call
(irb):2:in x' (irb):7:in call’
(irb):7:in irb_binding' /usr/lib/ruby/1.9.1/irb/workspace.rb:80:in eval’

Even for such a seemingly simple case if one goes beyond one’s
expectations things are more complex than they seem on initial sight.

Kind regards

robert

Robert K. wrote in post #1102170:

On Mon, Mar 18, 2013 at 8:39 PM, Marcin R. [email protected] wrote:

Robert K. wrote in post #1102151:

On Mon, Mar 18, 2013 at 5:50 PM, Marcin Rzeźnicki

Sorry for late answer, busy day at work.

I am not sure what you expect should be called “bound correctly”.
Basically what you did is you said D#curse should be D#greeting
(either via define_method as shown above or alias). That means, D’s
method #curse behaves like D’s #greeting and hence ultimately invokes
C#greeting and not C#curse.

When I imagine hypothetical pseudo-code implementation of define_method
I’d rather see: object[:method_name] = method_instance.code, than
object[:method_name] = method_instance :slight_smile:

Your expectation was clear. But others may have different
expectations. We are discussing to try to find out what might be more
reasonable or what expectations might be shared by more people. :slight_smile:
That’s why I questioned whether the term “correctly” was appropriate
here.

Well, you’re right - my wording implied that existing behavior is
somehow ‘incorrect’ or buggy, while certainly it works as intended.
Sorry for this.

Btw, somehow your chain example seems incomplete: is #chain a method
defined in Module? What about method names? I would have expected
the chained method name to be given as argument.

Ah yes, I omitted lots of details for brevity, trying to get to the
bottom line, if you will. Basically, chain is called from method_added
hook. When you include the module it installs this hook, adds class
method to specify the name of a “chained” method, listens for
subclassing to get into child class to do the trick again etc., but I
felt that this boilerplate was irrelevant to my problem.

Maybe you left out too many details. :slight_smile: It usually helps to provide
a small and above all complete example that others can execute:
http://sscce.org/

Ah, it’s nowhere near finished :slight_smile: I think that we should stick to
greetings/curses problem, that’s my problem distilled.

I will certainly try to find it. Many thanks. BTW, judging from example
you posted (I have not yet run it, though) it exhibits the same problem
as my implementation - calling super from #_m would call #m in parent
class which could call #_m in child again.

Yes, super and alias don’t mix well. You could argue that a method’s
behavior would change depending on the name used to invoke it if Ruby
was made to match your expectation. There are two downsides:

  1. Could be viewed as an aesthetic issue: the behavior of code would
    change after the definition of the method.

Yes, well, it’s not that I want whole Ruby to be changed because of my
whining. I guess what I was trying to ask was if there is some obvious
solution that I overlooked (you know, kind of: “Geez, yet another rookie
having problems with ‘super’. Listen man, do yourself a favor and do it
like this and this, it’s been solved 1000 times before”)

  1. As a consequence of changed behavior there would be a runtime
    effect: while executing the interpreter would have to have knowledge
    of the name used to invoke a method. Now you could argue that this
    knowledge does actually exist (caller provides it) but it may incur a
    runtime hit - for just a small amount of use cases.

I don’t think so, I mean, obviously super already has to know the name
of the method it’s invoked from to do a lookup. The question is - where
the name is taken from. If method used its “actual” name instead of
“original” name then we’re fine with super itself. An additional cost I
can see lurking here is that define/alias method would need to copy a
method instance (if called with one as an argument) and change its name
to reflect aliasing, rather than just reference the original one.
Anyhow, this is purely hypothetical.

BTW, having given it a little thought I think that I can easily check
for the condition of being called from super myself. What it takes is
just a flag that signals that we’re recursively called and a check what
real ‘self’ is. I still need to flesh out the details but I guess this
might work.

Robert K. wrote in post #1102288:

I don’t think so, I mean, obviously super already has to know the name
of the method it’s invoked from to do a lookup.

Yes, but with the current solution the name can be baked into the
compiled version of the Ruby code. While with your suggestion the
name would have to be retrieved for every single call. That is the
difference.

Is there anything like compiled Ruby code? I’m curious. Could you
elaborate?

BTW, having given it a little thought I think that I can easily check
for the condition of being called from super myself. What it takes is
just a flag that signals that we’re recursively called and a check what
real ‘self’ is. I still need to flesh out the details but I guess this
might work.

Good. I don’t understand why “self” might change when chaining method
calls on the same instance but I truest you to sort that out. :slight_smile:

Ok, I solved this. My description was rather clumsy, but code speaks
more than thousand words. So, here it is. It is not tested thoroughly
though.

module Chain
attr_accessor :next

def self.init_chain(chain)
  chain.each_cons(2) { |first, last| first.next = last }
  chain.last.next = nil

  chain.first
end

def self.included(host)
  host.extend(ChainClassMethods)
  host.instance_variable_set(:@__chain_method, nil)
end

module ChainClassMethods
  def chain_method(method_name)
    raise "There is another chain method already defined in this 

module: #{@__chain_method}" if @__chain_method

    @__chain_method = method_name
    chain if method_defined? method_name
  end

  def method_added(method_name)
    chain if @__chain_method == method_name and not 

instance_variable_get(:@__in_chain)
end

  def inherited(subclass)
    subclass.instance_variable_set(:@__chain_method, 

@__chain_method)
end

  private
  def chain
    new_method_name = "__#{@__chain_method}"
    chain_method    = @__chain_method

    @__in_chain = true

    alias_method new_method_name, chain_method
    private new_method_name
    chained_method = instance_method(new_method_name)

    define_method(chain_method) do |*args|
      if instance_variable_get(:@_in_chain)
        chained_method.bind(self).call(*args) do |*yielded_args|
          begin
            new_args = yielded_args.empty? ? args : yielded_args
            self.next.send chain_method, *new_args
          end if self.next
        end
      else
        @_in_chain = true
        send new_method_name, *args do |*yielded_args|
          begin
            new_args = yielded_args.empty? ? args : yielded_args
            self.next.send chain_method, *new_args
          end if self.next
        end
        remove_instance_variable :@_in_chain
      end
    end

    remove_instance_variable :@__in_chain
  end
end

end

Comments are welcome.
The trick here is to store method instance in a closure: chained_method
= instance_method(new_method_name) and keep a flag signalling if the
call is recursive (@_in_chain). If it is not then we simply pass the
message to the original method adding a block that does the chaining
(call it premature optimization if you will, but I have a feeling that
#send is somewhat better to use in the base case because of the cost of
method binding - at least one new object needs to be created every time
we’re binding). This block gives user the ability to write method like
this:

chain_method :hello
def hello
p “Hello”
yield
end

If call is recursive than it is either ‘super’ call or plain recursion,
we don’t care which one it is. In this case we’re binding method
reference that is accessible from closure we’re in to self and call it
via #call, thus bypassing polymorphic call that caused troubles in the
first place. Makes sense? I’ll be happy to hear your take on this.

Kind regards

robert

On Tue, Mar 19, 2013 at 2:46 PM, Marcin R. [email protected] wrote:

Robert K. wrote in post #1102170:

On Mon, Mar 18, 2013 at 8:39 PM, Marcin R. [email protected] wrote:

Robert K. wrote in post #1102151:

On Mon, Mar 18, 2013 at 5:50 PM, Marcin Rzeźnicki

Sorry for late answer, busy day at work.

No problem at all. After all, you were the one looking for a solution.
:slight_smile:

  1. Could be viewed as an aesthetic issue: the behavior of code would
    change after the definition of the method.

Yes, well, it’s not that I want whole Ruby to be changed because of my
whining. I guess what I was trying to ask was if there is some obvious
solution that I overlooked (you know, kind of: “Geez, yet another rookie
having problems with ‘super’. Listen man, do yourself a favor and do it
like this and this, it’s been solved 1000 times before”)

I’m not aware of any right now.

  1. As a consequence of changed behavior there would be a runtime
    effect: while executing the interpreter would have to have knowledge
    of the name used to invoke a method. Now you could argue that this
    knowledge does actually exist (caller provides it) but it may incur a
    runtime hit - for just a small amount of use cases.

I don’t think so, I mean, obviously super already has to know the name
of the method it’s invoked from to do a lookup.

Yes, but with the current solution the name can be baked into the
compiled version of the Ruby code. While with your suggestion the
name would have to be retrieved for every single call. That is the
difference.

The question is - where the name is taken from.

Exactly.

If method used its “actual” name instead of
“original” name then we’re fine with super itself. An additional cost I
can see lurking here is that define/alias method would need to copy a
method instance (if called with one as an argument) and change its name
to reflect aliasing, rather than just reference the original one.
Anyhow, this is purely hypothetical.

Yes, that might be a solution.

BTW, having given it a little thought I think that I can easily check
for the condition of being called from super myself. What it takes is
just a flag that signals that we’re recursively called and a check what
real ‘self’ is. I still need to flesh out the details but I guess this
might work.

Good. I don’t understand why “self” might change when chaining method
calls on the same instance but I truest you to sort that out. :slight_smile:

Kind regards

robert

Robert K. wrote in post #1102581:

On Thu, Mar 21, 2013 at 11:31 AM, Marcin R. [email protected]
wrote:

Ok, I solved this. My description was rather clumsy, but code speaks
more than thousand words.

I usually prefer a written explanation of the purpose of the code.
The code is the solution but the goal does not always become apparent
from looking at code.

So true, but I am hoping my explanation given below was sufficient.

This block gives user the ability to write method like
this:

chain_method :hello
def hello
p “Hello”
yield
end

Why would I want to do that? What is that supposed to do?

As I mentioned previously my goal is to create easy to use
implementation of chain pattern. You can do it manually, calling
next-in-line via some sort of reference you keep (“next” in my case),
but I feel that we can do better than this. My idea is to keep
boilerplate in chain module and let implementations yield (because
that’s quite natural way of doing things like this in Ruby - you
temporarily yield control to regain it later) when they need to pass the
control down the chain.

If call is recursive than it is either ‘super’ call or plain recursion,

Super call is not recursion. Recursion is when a method invokes
itself. Super calls are used to augment a super class’s
implementation of a method with additional logic specific to the
derived class.

Yes, so I said - EITHER super OR recursive.

we don’t care which one it is. In this case we’re binding method
reference that is accessible from closure we’re in to self and call it
via #call, thus bypassing polymorphic call that caused troubles in the
first place. Makes sense? I’ll be happy to hear your take on this.

I still don’t understand what you are up to and what your ultimate goal
is.

Hope I’ve already made myself clear. Thanks for your input.

On Thu, Mar 21, 2013 at 11:31 AM, Marcin R. [email protected]
wrote:

Is there anything like compiled Ruby code? I’m curious. Could you
elaborate?

AFAIK the Ruby code is parsed and compiled to some internal byte code
representation. For more details you would have to use your favorite
search engine or look at MRI source (and JRuby source and sources of
the other Rubies).

Ok, I solved this. My description was rather clumsy, but code speaks
more than thousand words.

I usually prefer a written explanation of the purpose of the code.
The code is the solution but the goal does not always become apparent
from looking at code.

This block gives user the ability to write method like
this:

chain_method :hello
def hello
p “Hello”
yield
end

Why would I want to do that? What is that supposed to do?

If call is recursive than it is either ‘super’ call or plain recursion,

Super call is not recursion. Recursion is when a method invokes
itself. Super calls are used to augment a super class’s
implementation of a method with additional logic specific to the
derived class.

we don’t care which one it is. In this case we’re binding method
reference that is accessible from closure we’re in to self and call it
via #call, thus bypassing polymorphic call that caused troubles in the
first place. Makes sense? I’ll be happy to hear your take on this.

I still don’t understand what you are up to and what your ultimate goal
is.

Cheers

robert

Marcin R. wrote in post #1102590:

Robert K. wrote in post #1102581:

Yes, so I said - EITHER super OR recursive.

Ooops, I didn’t - I wrote “If call is recursive” where I should’ve
written “if call is flagged as in_chain”. My apologies.

On Thu, Mar 21, 2013 at 1:20 PM, Marcin R. [email protected] wrote:

Robert K. wrote in post #1102581:

On Thu, Mar 21, 2013 at 11:31 AM, Marcin R. [email protected]
wrote:

I usually prefer a written explanation of the purpose of the code.
The code is the solution but the goal does not always become apparent
from looking at code.

So true, but I am hoping my explanation given below was sufficient.

Why would I want to do that? What is that supposed to do?

As I mentioned previously my goal is to create easy to use
implementation of chain pattern.

Are you talking about “chain of responsibility”?

http://c2.com/cgi/wiki?ChainOfResponsibilityPattern

You can do it manually, calling
next-in-line via some sort of reference you keep (“next” in my case),
but I feel that we can do better than this. My idea is to keep
boilerplate in chain module and let implementations yield (because
that’s quite natural way of doing things like this in Ruby - you
temporarily yield control to regain it later) when they need to pass the
control down the chain.

I don’t see the advantage of using “yield” over any other method name.
It seems you are going through hoops just to allow yield to delegate
to another instance. I don’t think it’s worthwhile. For me this
would be good enough:

ChainedBase = Struct.new :delegate do
def chain(a, &b)
m = caller[0][%r{`(.
?)'\z}, 1]
d = delegate and d.send(m, *a, &b)
end
end

class Der < ChainedBase
def foo x
puts “entry Der”
chain x
puts “exit Der”
end
end

class Catcher
def method_missing(m, *a, &b)
printf “Caught: %s(%s)\n”, m, a.map(&:inspect).join(', ')
end
end

o = Der.new
o.delegate = Catcher.new
o.foo 123

If call is recursive than it is either ‘super’ call or plain recursion,

Super call is not recursion. Recursion is when a method invokes
itself. Super calls are used to augment a super class’s
implementation of a method with additional logic specific to the
derived class.

Yes, so I said - EITHER super OR recursive.

Yeah, but the fact that you mix them together is suspicious. Chain of
responsibility is all about (conditional) delegation to another
instance. Calling superclass methods does not fit that pattern
because it is the same instance.

Hope I’ve already made myself clear.

It seems so.

Thanks for your input.

You’re welcome

robert

On Thu, Mar 21, 2013 at 2:34 PM, Robert K.
[email protected] wrote:

PS: Another way to implement this would be completely external:

chain = [ … ]

chain.find do |obj|
obj.handle 123
end

With the convention that a successful handling leads to true return, for
example

class Handler
def handle(x)
wants_to_handle(x).tap do |yes|
yes or return false

end
end
end