Difference between alias and alias_method

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 :old_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

···

On Dec 17, 12:42 pm, Chan Sammy <csa...@gmail.com> wrote:

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 :old_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)

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:

···

On Dec 17, 12:42 pm, Chan Sammy <csa...@gmail.com> wrote:

class T
def initialize()
   puts "T's initialize"
end
def self.redefine
   self.module_eval do
     alias old_initialize initialize
     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)

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(). :slight_smile:

  Paolo Perrotta
  Bologna, Italy

···

On Dec 17, 11:12 pm, "jwmerr...@gmail.com" <jwmerr...@gmail.com> wrote:

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.

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.

···

On 12/18/07, Paolo Nusco Perrotta <paolo.nusco.perrotta@gmail.com> wrote:

On Dec 17, 11:12 pm, "jwmerr...@gmail.com" <jwmerr...@gmail.com> > wrote:
> 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(). :slight_smile:

  Paolo Perrotta
  Bologna, Italy