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?

On Aug 14, 9:35 am, Marcos [email protected] 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?

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 Fri, Aug 14, 2009 at 4:35 PM, Marcos[email protected] wrote:

   def real_method() "Child" 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?

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 Aug 14, 10:31 am, Marcos [email protected] wrote:

    def real_method() "Child" end
end

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

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 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?

Gary W. wrote:

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.

Hi –

On Fri, 14 Aug 2009, Marcos wrote:

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.

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

Hi,

In message “Re: Class method aliased in superclass bypasses subclass
overrides”
on Sat, 15 Aug 2009 04:31:35 +0900, Gary W. [email protected]
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.

On Fri, Aug 14, 2009 at 10:46 PM, Joel
VanderWerf[email protected] wrote:

construct for this purpose, since the above is so compact and clear.


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

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

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.

On Aug 15, 8:31 am, 7stud – [email protected] wrote:

end

end

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.

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs