Class method aliased in superclass bypasses subclass overrides

This seems like it should work:

    class Parent
        class << self
            def real_method() "Parent" end
            alias :fake_method :real_method
        end
    end

    class Child < Parent
        def real_method() "Child" end
    end

But it doesn't:

       Child.fake_method # ==> returns "Parent" instead of "Child"

If I replace the alias with a real method definition, e.g.

        def fake_method() real_method end

then it works the way I expect (Child.fake_method returns "Child").
So what is it about "alias" that bypasses the override? Do I have to
replace my aliases with extra wrapper methods to get the behavior I'm
looking for?

As far as I can tell (or explain), alias and alias_method work by
creating a new copy of the method. One way to think about it is if you
had the block stored in a variable because you created the first
method like so

    class Blah
      meth = Proc.new { puts 'hi' }
      define_method :first, &meth
    end

Then aliasing the method like `alias :copy :first` is the same as
`define_method :copy, &meth`.

I ran into problems with the same sort of behavior when I was trying
to test-drive an addition of a simple alias for a complicated method,
and I assumed that I could simply test that calling the alias called
the original method with the same arguments. Nope! Calling the alias
went through the same complicated steps as the original. So I changed
the alias_method line to a wrapper function and went on my merry way.

···

On Aug 14, 9:35 am, Marcos <markjr...@gmail.com> wrote:

So what is it about "alias" that bypasses the override? Do I have to
replace my aliases with extra wrapper methods to get the behavior I'm
looking for?

--
-yossef

I do not see anything surprising here, you aliased a method in parent
and not in child. When calling child's fake method there is none and
the lookup finds the parent's method.
When however you wrap the parent's methods after having found parent's
#fake it calls
real which is found in the child. Note that parent's #real is never
called in none of the two cases!

HTH
Robert

···

On Fri, Aug 14, 2009 at 4:35 PM, Marcos<markjreed@gmail.com> wrote:

This seems like it should work:

class Parent
class << self
def real_method() "Parent" end
alias :fake_method :real_method
end
end

class Child < Parent
def real_method() "Child" end
end

But it doesn't:

  Child\.fake\_method \# ==&gt; returns &quot;Parent&quot; instead of &quot;Child&quot;

If I replace the alias with a real method definition, e.g.

   def fake\_method\(\) real\_method end

then it works the way I expect (Child.fake_method returns "Child").
So what is it about "alias" that bypasses the override? Do I have to
replace my aliases with extra wrapper methods to get the behavior I'm
looking for?

--
module Kernel
  alias_method :λ, :lambda
end

Hi --

This seems like it should work:

   class Parent
       class << self
           def real_method() "Parent" end
           alias :fake_method :real_method

You don't have to use symbols there; you can do:

   alias fake_method real_method

because alias is a keyword, not a method, so it can take "raw"
identifiers.

       end
   end

   class Child < Parent
       def real_method() "Child" end

You mean def self.real_method, I think.

   end

But it doesn't:

      Child.fake_method # ==> returns "Parent" instead of "Child"

If I replace the alias with a real method definition, e.g.

       def fake_method() real_method end

then it works the way I expect (Child.fake_method returns "Child").
So what is it about "alias" that bypasses the override? Do I have to
replace my aliases with extra wrapper methods to get the behavior I'm
looking for?

The aliasing just means that there's now a method called
Parent.fake_method. It doesn't add any methods to any class other than
the class where it's executed (in this case, the singleton class of
Parent). Basically, creating an alias has the same footprint as
writing a method definition.

David

···

On Fri, 14 Aug 2009, Marcos wrote:

--
David A. Black / Ruby Power and Light, LLC / http://www.rubypal.com
Q: What's the best way to get a really solid knowledge of Ruby?
A: Come to our Ruby training in Edison, New Jersey, September 14-17!
    Instructors: David A. Black and Erik Kastner
    More info and registration: http://rubyurl.com/vmzN

Small correction - that should be "def self.real_method". All class
methods, not instance methods...

···

On Aug 14, 10:31 am, Marcos <markjr...@gmail.com> wrote:

This seems like it should work:

class Parent
    class &lt;&lt; self
        def real\_method\(\) &quot;Parent&quot; end
        alias :fake\_method :real\_method
    end
end

class Child &lt; Parent
    def real\_method\(\) &quot;Child&quot; end
end

I find it mildly annoying that 'alias' doesn't actually alias the
method (i.e. multiple names for the same thing). Instead, alias
just replicates an existing method body and associates a new
name with the replica. Seems like 'replicate' would be a better
keyword for the current semantics.

I also have the inability to ever remember which argument to alias
is the new name and which argument is the old name.

Did 'alias' work differently in the early days of Ruby such that
the semantics changed but not the keyword?

···

On Aug 14, 2009, at 2:25 PM, David A. Black wrote:

The aliasing just means that there's now a method called
Parent.fake_method. It doesn't add any methods to any class other than
the class where it's executed (in this case, the singleton class of
Parent). Basically, creating an alias has the same footprint as
writing a method definition.

I believe your alias version is equivalent to this:

···

==========
class Parent
  Parent.real_method
    "Parent"
  end

  Parent.fake_method #alias creates a copy of real_method
    "Parent"
  end

end

and your wrapped version is this:

=========
class Parent
  def Parent.real_method
    "Parent"
  end

  def Parent.fake_method
    real_method #<-----**BIG DIFFERENCE**
  end
end

Those Parent classes are clearly not the same. If you add the following
code to your wrapped version:

=========
class Child < Parent
  def self.real_method
    "Child"
  end
end

puts Child.fake_method

--output:--
Child

the message "fake_method" is sent to the Child object (=a class object).
The Child object has no method named "fake_method" defined on it, e.g.
def Child.fake_message, so lookup proceeds to the superclass class
object, i.e. Parent. The Parent object does have the method
"fake_method" defined on it, so Parent.fake_method is executed.
Parent.fake_method really looks like this:

def Parent.fake_method
  self.real_method
end

In this case, self is the Child object--because when you write:

puts Child.fake_method

the fake_method message gets sent to the Child object--in other words
Child is calling fake_method, and the caller is self inside a method.
Therefore, calling self.real_method (inside fake_method) is equivalent
to calling Child.real_method. And calling Child.real_method sends the
message real_method to the Child object. As a consequence, a new lookup
begins starting with the Child object. Because Child has a method
called real_method defined on it, Child.real_method executes.

It's highly probable that the above description contains some factual
errors, but the esteemed members who previously posted above will surely
correct them below.

--
Posted via http://www.ruby-forum.com/.

Gary Wright wrote:

I find it mildly annoying that 'alias' doesn't actually alias the
method (i.e. multiple names for the same thing). Instead, alias
just replicates an existing method body and associates a new
name with the replica. Seems like 'replicate' would be a better
keyword for the current semantics.

I also have the inability to ever remember which argument to alias
is the new name and which argument is the old name.

Did 'alias' work differently in the early days of Ruby such that
the semantics changed but not the keyword?

+1 to all of above, albeit mildly for me too.

In practice I usually end up with

   def myalias(*a,&b); orig(*a,&b); end

even if it started out as an "alias". I don't mind not having a language construct for this purpose, since the above is so compact and clear.

···

--
       vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

Hi,

···

In message "Re: Class method aliased in superclass bypasses subclass overrides" on Sat, 15 Aug 2009 04:31:35 +0900, Gary Wright <gwtmp01@mac.com> writes:

Did 'alias' work differently in the early days of Ruby such that
the semantics changed but not the keyword?

FYI, alias worked as it is from the very early days of Ruby.

              matz.

In that case, 'alias' wouldn't alias anything; it just makes a copy,
which is a different thing altogether.

It seems more likely to be something likc Yossef said:

block = Proc.new { "Parent" }
define_method :real_method, block
define_method :fake_method, block

Where the same body (rather than two identical copies) is used for
both methods; the traditional CS kind of "alias". In UNIX terms, it's
an ln, not a cp.

To stretch the analogy a bit, what I was expecting was more like "ln -
s". But clearly that's not correct, so I'll just stick with the
wrapper methods.

Thanks for all the replies.

···

On Aug 15, 8:31 am, 7stud -- <bbxx789_0...@yahoo.com> wrote:

I believe your alias version is equivalent to this:

==========
class Parent
Parent.real_method
"Parent"
end

Parent.fake_method #alias creates a copy of real_method
"Parent"
end

end

It is strange that as a Unix guy I have never been bothered by this.
As an important use case for my aliases (although I prefer the
alias_method method) I am often using this pattern:

   alias_method :__behavior__, :behavior
   remove_method :behavior # for 1.9
   define_method :behavior do ...
        ...
        __behavior__
   ...

thus the current behavior became second nature.

Maybe it would be nice to have a synonym method in Module that does
what you two expected from alias, that is being dynamically redefined
with its target.

Cheers
Robert

···

On Fri, Aug 14, 2009 at 10:46 PM, Joel VanderWerf<vjoel@path.berkeley.edu> wrote:

Gary Wright wrote:

I find it mildly annoying that 'alias' doesn't actually alias the
method (i.e. multiple names for the same thing). Instead, alias
just replicates an existing method body and associates a new
name with the replica. Seems like 'replicate' would be a better
keyword for the current semantics.

I also have the inability to ever remember which argument to alias
is the new name and which argument is the old name.

Did 'alias' work differently in the early days of Ruby such that
the semantics changed but not the keyword?

+1 to all of above, albeit mildly for me too.

In practice I usually end up with

def myalias(*a,&b); orig(*a,&b); end

even if it started out as an "alias". I don't mind not having a language
construct for this purpose, since the above is so compact and clear.

--
vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

--
module Kernel
  alias_method :λ, :lambda
end