Alias versus method_missing

All,

Before I make this harder than it is, I wanted to double-check. Let’s
say I have a base class:

  class Base
    def foo
      puts "inside Base#foo"
    end
  end

and another class derived from Base:

  class Derived < Base
    def foo
      puts "inside Derived#foo"
    end
  end

Now suppose I’d like to set up “bar” as an alias for “foo”, such that if
I invoke “bar” on a Base instance (or an instance of any of Bar’s
subclasses) that it will turn around and call “foo” for that instance
instead, i.e.

  b = Base.new
  d = Derived.new

  b.bar -> prints "inside Base#foo"
  d.bar -> prints "inside Derived#foo"

I’m finding that if I simply add an alias in the base class:

  class Base
    alias bar foo
  end

that doesn’t cut it; “bar” always invokes Base#foo. And I guess I
understand why. But I was trying to figure out if there’s an alternative
that gets me what I really wanted (sort-of a “virtual alias”).

I think I can make it work using method_missing instead of alias, e.g.

  class Base
    def method_missing(mid, *args)
      case mid
        when :bar
          foo(*args)
        else
          super # hand off to Base's base class...
      end
    end
  end

but this is obviously a lot more verbose (especially since I’ll
ultimately have lots of aliases, in lots of classes). Is there some more
compact approach that I’m forgetting about?

Thanks in advance,

Lyle

Hi,

How about starting with the great-great-grandchild, and then 'eval’ing the
alias all the way up to the root?

Regards,

Bill

···

============================================================================
Lyle Johnson lyle@knology.net wrote:

  class Base
    alias bar foo
  end

that doesn’t cut it; “bar” always invokes Base#foo. And I guess I
understand why. But I was trying to figure out if there’s an alternative
that gets me what I really wanted (sort-of a “virtual alias”).

I think I can make it work using method_missing instead of alias, e.g.

(deleted)

but this is obviously a lot more verbose (especially since I’ll
ultimately have lots of aliases, in lots of classes). Is there some more
compact approach that I’m forgetting about?

Lyle Johnson wrote:

All,

Before I make this harder than it is, I wanted to double-check. Let’s
say I have a base class:

 class Base
   def foo
     puts "inside Base#foo"
   end
 end

and another class derived from Base:

 class Derived < Base
   def foo
     puts "inside Derived#foo"
   end
 end

 class Base
   def method_missing(mid, *args)
     case mid
       when :bar
         foo(*args)
       else
         super # hand off to Base's base class...
     end
   end
 end

Another reason not to use method_missing:

Derived.new.bar # ==> inside Derived#foo

class Object
def bar
puts “inside Object#bar”
end
end

Derived.new.bar # ==> inside Object#bar

The superclass has overriden the subclass!

Lyle Johnson wrote:

understand why. But I was trying to figure out if there’s an alternative
that gets me what I really wanted (sort-of a “virtual alias”).

It’s a little less efficient, but this seems to be virtual:

class Base
def bar; foo; end
end

There must be a way to use Class#inherited to good effect, but the
following doesn’t seem to work:

class Base
def self.inherited(sub)
sub.class_eval {alias_method :bar, :foo}
end
end

Derived.new.bar # ==> inside Base#foo

However,

Derived.class_eval {alias_method :bar, :foo}
Derived.new.bar # ==> inside Derived#foo

Anyone understand why? (I’m using 1.6.7, and maybe this would be
different in a recent 1.7.)

William Djaja Tjokroaminata wrote:

How about starting with the great-great-grandchild, and then 'eval’ing the
alias all the way up to the root?

OK, I am too dense to understand what you’re suggesting :wink: Could you
maybe give me a brief example (in code) of the approach you’re suggesting?

Hi –

···

On Sun, 29 Sep 2002, Joel VanderWerf wrote:

Lyle Johnson wrote:

understand why. But I was trying to figure out if there’s an alternative
that gets me what I really wanted (sort-of a “virtual alias”).

It’s a little less efficient, but this seems to be virtual:

class Base
def bar; foo; end
end

There must be a way to use Class#inherited to good effect, but the
following doesn’t seem to work:

class Base
def self.inherited(sub)
sub.class_eval {alias_method :bar, :foo}
end
end

Derived.new.bar # ==> inside Base#foo

However,

Derived.class_eval {alias_method :bar, :foo}
Derived.new.bar # ==> inside Derived#foo

Anyone understand why? (I’m using 1.6.7, and maybe this would be
different in a recent 1.7.)

I get two #foo’s with 1.6.7.

David


David Alan Black | Register for RubyConf 2002!
home: dblack@candle.superlink.net | November 1-3
work: blackdav@shu.edu | Seattle, WA, USA
Web: http://pirate.shu.edu/~blackdav | http://www.rubyconf.com

Joel VanderWerf wrote:

Another reason not to use method_missing:

Derived.new.bar # ==> inside Derived#foo

class Object
def bar
puts “inside Object#bar”
end
end

Derived.new.bar # ==> inside Object#bar

The superclass has overriden the subclass!

Ah, this is an interesting consequence I hadn’t thought of. For my
particular application I’m not concerned about this happening and, if
someone does it, that’s their problem :wink:

But you’re correct that it’s flawed for the general case…

Joel VanderWerf wrote:

It’s a little less efficient, but this seems to be virtual:

class Base
def bar; foo; end
end

Perhaps less efficient than an alias, but certainly more efficient than
the convoluted method_missing approach I was considering. I like this
because (as you’ve shown) I can still squeeze each “virtual alias” on to
a single line.

There must be a way to use Class#inherited to good effect, but the
following doesn’t seem to work:

Assuming we were able to make this kind of approach work, I wonder which
one’s more efficient in terms of storage. In other words, assume the
extreme case that Base wants a lot of aliases for its methods. If you
just define those “aliases” as differently-named instance methods (the
approach described above) you’ve added N new instance methods total. On
the other hand, if set up true aliases in each of Base’s subclasses (via
the Class#inherited trick) then it’s N*M aliases (where M is the number
of subclasses).

Hi Lyle,

This is just an example; I am sure you can improve it further according to
your need. Here we use one of the powers of scripting/interpreted
language, which is that we can generate code on-the-fly.

Regards,

Bill

···

class Base
def foo
puts “inside Base#foo”
end
end

class Derived < Base
def foo
puts “inside Derived#foo”
end
end

class Final < Derived
def foo
puts “inside Final#foo”
end
end

def set_alias (child)
until child == Object
eval “class #{child.name}\n alias bar foo\n end”
child = child.superclass
end
end

set_alias (Final)
Final.new.bar
Derived.new.bar
Base.new.bar

===========================================================================
Lyle Johnson lyle@users.sourceforge.net wrote:

William Djaja Tjokroaminata wrote:

How about starting with the great-great-grandchild, and then 'eval’ing the
alias all the way up to the root?

OK, I am too dense to understand what you’re suggesting :wink: Could you
maybe give me a brief example (in code) of the approach you’re suggesting?

dblack@candle.superlink.net wrote:

I get two #foo’s with 1.6.7.

But whose #foo’s are they?

Is this what you are doing?

class Base
def foo
puts “inside Base#foo”
end

 def self.inherited(sub)
   sub.class_eval {alias_method :bar, :foo}
 end

end

class Derived < Base
def foo
puts “inside Derived#foo”
end
end

Derived.new.bar # ==> inside Base#foo

Derived.class_eval {alias_method :bar, :foo}

Derived.new.bar # ==> inside Derived#foo

So it seems that #alias_method has no effect when used within #inherited.

Hi –

I get two #foo’s with 1.6.7.

But whose #foo’s are they?

Whoops, I meant to say: two Derived’s.

Is this what you are doing?
[snip]

I had included

class Base; def bar; foo; end; end

which I now realize was a different point, not part of that code.

David

···

On Sun, 29 Sep 2002, Joel VanderWerf wrote:

dblack@candle.superlink.net wrote:


David Alan Black | Register for RubyConf 2002!
home: dblack@candle.superlink.net | November 1-3
work: blackdav@shu.edu | Seattle, WA, USA
Web: http://pirate.shu.edu/~blackdav | http://www.rubyconf.com

So it seems that #alias_method has no effect when used within #inherited.

No, it has an effect but when ::inherited is called Derived#foo not yet
exist.

Guy Decoux