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?
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?
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
But you’re correct that it’s flawed for the general case…
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).
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