Difference between alias and alias_method

C

Chan Sammy

In the example below, I really can't sort out why using alias_method
will work, while using alias won't. Could someone shred me some light
on this? Thanks.

class T
def initialize()
puts "T's initialize"
end
def self.redefine
alias old_initialize initialize
#alias_method :eek:ld_initialize, :initialize
self.module_eval do
define_method :initialize do
old_initialize(1)
end
end
end
end

class S < T
def initialize(int)
puts "S's initialize:#{int}"
end
redefine()
end
S.new

==========================
Using alias:
in `old_initialize': wrong number of arguments (1 for 0) (ArgumentError)
(T's initialize was called)

Using alias_method:
S's initialize:1
(S's initialize was called, as expected)
 
J

jwmerrill

In the example below, I really can't sort out why using alias_method
will work, while using alias won't. Could someone shred me some light
on this? Thanks.

class T
def initialize()
puts "T's initialize"
end
def self.redefine
alias old_initialize initialize
#alias_method :eek:ld_initialize, :initialize
self.module_eval do
define_method :initialize do
old_initialize(1)
end
end
end
end

class S < T
def initialize(int)
puts "S's initialize:#{int}"
end
redefine()
end
S.new

==========================
Using alias:
in `old_initialize': wrong number of arguments (1 for 0) (ArgumentError)
(T's initialize was called)

Using alias_method:
S's initialize:1
(S's initialize was called, as expected)

Don't know exactly why, but wrapping alias in a class_eval seems to
fix the problem:

class_eval("alias old_initialize initialize")

Using ri, I couldn't even find who exactly alias belongs to (i.e. is
it defined in Kernel, Object, Module, or what, and is it a class
method of one of these?) Hopefully someone else can weigh in and
clear this up.

Jason
 
B

Brian Adkins

In the example below, I really can't sort out why using alias_method
will work, while using alias won't. Could someone shred me some light
on this? Thanks.

I believe it's a scoping issue. Move the alias statement so that it's
within the module_eval block as below:
 
P

Paolo \Nusco\ Perrotta

Don't know exactly why, but wrapping alias in a class_eval seems to
fix the problem:

class_eval("alias old_initialize initialize")

Using ri, I couldn't even find who exactly alias belongs to (i.e. is
it defined in Kernel, Object, Module, or what, and is it a class
method of one of these?) Hopefully someone else can weigh in and
clear this up.

This is because "alias" is not a method - it's a keyword (that trips
me up every time I put a comma between the old and new method name,
and the compiler complains).

You can use "alias" in two contexts. You normally use it in a class
definition to alias an instance method of the class. It's not enough
that the class is "self" - you really must be inside the class
definition. That's why this works:

MyClass.class_eval{ alias :to_string :to_s }

while this doesn't (at least, not as you might think):

MyClass.instance_eval{ alias :to_string :to_s }

What happens if you use alias *outside* a class definition instead?
When you do that, you're actually aliasing a method of "self" (the
current object) to a singleton method:

irb(main):001:0> c = Object.new
=> #<Object:0x2e8f0d8>
irb(main):002:0> c.instance_eval { alias :clazz :class }
=> nil
irb(main):003:0> c.clazz
=> Object

(If you don't know what a "singleton method" is, you can find many
threads about the topic on this group. Be advised that this will
require you to take a journey into Ruby metaprogramming).

As a special case of the above, if "self" is a class, then you're
aliasing an existing method to a singleton method of the class - and a
singleton method of the class is what we usually call a class method.
That's why instance_eval() might surprise you:

irb(main):003:0> String.instance_methods[0..1]
=> ["%", "select"]
irb(main):004:0> String.instance_eval { alias :x :instance_methods }
=> nil
irb(main):006:0> String.x[0..1]
=> ["%", "select"]

Bottom line: if you want "alias" to behave as you probably want it to
behave, do like Jason suggested and wrap it in a class_eval(). :)

Paolo Perrotta
Bologna, Italy
 
C

Chan Sammy

Agree with Brian. I think the difference is that for alias, how the
method names are resolved depends statically on the context the alias
statement is under, and for alias_method, the symbols are resolved to
methods dynamically:

class T
def self.redefine
alias bar foo
#alias_method :bar, :foo
end
def foo ; puts "T's foo" ; end
end

class S < T
def foo ; puts "S's foo" ; end
redefine()
end

S.new.bar
puts T.instance_methods.grep(/bar/)

For alias, bar and foo are resolved to T's instance methods.
For alias_method, :bar and :foo are resolved to S's instance methods.

And this is what surprised me. I'm not sure this is by design or by accident.

Don't know exactly why, but wrapping alias in a class_eval seems to
fix the problem:

class_eval("alias old_initialize initialize")

Using ri, I couldn't even find who exactly alias belongs to (i.e. is
it defined in Kernel, Object, Module, or what, and is it a class
method of one of these?) Hopefully someone else can weigh in and
clear this up.

This is because "alias" is not a method - it's a keyword (that trips
me up every time I put a comma between the old and new method name,
and the compiler complains).

You can use "alias" in two contexts. You normally use it in a class
definition to alias an instance method of the class. It's not enough
that the class is "self" - you really must be inside the class
definition. That's why this works:

MyClass.class_eval{ alias :to_string :to_s }

while this doesn't (at least, not as you might think):

MyClass.instance_eval{ alias :to_string :to_s }

What happens if you use alias *outside* a class definition instead?
When you do that, you're actually aliasing a method of "self" (the
current object) to a singleton method:

irb(main):001:0> c = Object.new
=> #<Object:0x2e8f0d8>
irb(main):002:0> c.instance_eval { alias :clazz :class }
=> nil
irb(main):003:0> c.clazz
=> Object

(If you don't know what a "singleton method" is, you can find many
threads about the topic on this group. Be advised that this will
require you to take a journey into Ruby metaprogramming).

As a special case of the above, if "self" is a class, then you're
aliasing an existing method to a singleton method of the class - and a
singleton method of the class is what we usually call a class method.
That's why instance_eval() might surprise you:

irb(main):003:0> String.instance_methods[0..1]
=> ["%", "select"]
irb(main):004:0> String.instance_eval { alias :x :instance_methods }
=> nil
irb(main):006:0> String.x[0..1]
=> ["%", "select"]

Bottom line: if you want "alias" to behave as you probably want it to
behave, do like Jason suggested and wrap it in a class_eval(). :)

Paolo Perrotta
Bologna, Italy
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,754
Messages
2,569,528
Members
45,000
Latest member
MurrayKeync

Latest Threads

Top