Defining a method vs aliasing it

Hi,

I'm not exactly sure why defining a method with "def methodname"
versus aliasing it would behave differently.

My example code:

---< snip >---

module O1
  def self.append_features(base)
      super
      base.extend(ClassMethods)
      base.class_eval do
        class << self
          alias_method :inherited_without_o1, :inherited
          alias_method :inherited, :inherited_with_o1
        end
      end
      puts "Including O1 into #{base.inspect}"
  end

  module ClassMethods
    def inherited_with_o1(child)
      puts "O1: BEFORE WITHOUT"
      inherited_without_o1(child)
      puts "O1: AFTER WITHOUT"
      puts "O1: #{child.inspect}"
    end
  end
end

module O2
  def self.append_features(base)
      super
      puts "Including O2 into #{base.inspect}"
      base.class_eval do
        class << self
          alias_method :inherited_without_o2, :inherited
        end
      end
      base.extend(ClassMethods)
  end

  module ClassMethods
    def inherited(child)
      puts "O2: BEFORE WITHOUT"
      inherited_without_o2(child)
      puts "O2: AFTER WITHOUT"
      puts "O2: #{child.inspect}"
    end
  end
end

class Override
  include O1
  include O2
end

class Child1 < Override
end

class Child2 < Child1
end

class Child3 < Override
end

---< snip >---

This prints:

Including O1 into Override
Including O2 into Override
O1: BEFORE WITHOUT
O1: AFTER WITHOUT
O1: Child1
O1: BEFORE WITHOUT
O1: AFTER WITHOUT
O1: Child2
O1: BEFORE WITHOUT
O1: AFTER WITHOUT
O1: Child3

If I instead modify O2 to use the same approach as O1, I get the
expected output:

Including O1 into Override
Including O2 into Override
O2: BEFORE WITHOUT
O1: BEFORE WITHOUT
O1: AFTER WITHOUT
O1: Child1
O2: AFTER WITHOUT
O2: Child1
O2: BEFORE WITHOUT
O1: BEFORE WITHOUT
O1: AFTER WITHOUT
O1: Child2
O2: AFTER WITHOUT
O2: Child2
O2: BEFORE WITHOUT
O1: BEFORE WITHOUT
O1: AFTER WITHOUT
O1: Child3
O2: AFTER WITHOUT
O2: Child3

Why would using an alias to create the new "inherited" work, but a
"def inherited" not?

Help much appreciated..
Leon

Hi,

I'm not exactly sure why defining a method with "def methodname"
versus aliasing it would behave differently.

My example code:

---< snip >---

module O1
  def self.append_features(base)
      super
      base.extend(ClassMethods)
      base.class_eval do
        class << self
          alias_method :inherited_without_o1, :inherited
          alias_method :inherited, :inherited_with_o1
        end
      end
      puts "Including O1 into #{base.inspect}"
  end

  module ClassMethods
    def inherited_with_o1(child)
      puts "O1: BEFORE WITHOUT"
      inherited_without_o1(child)
      puts "O1: AFTER WITHOUT"
      puts "O1: #{child.inspect}"
    end
  end
end

module O2
  def self.append_features(base)
      super
      puts "Including O2 into #{base.inspect}"
      base.class_eval do
        class << self
          alias_method :inherited_without_o2, :inherited
        end
      end
      base.extend(ClassMethods)
  end

  module ClassMethods
    def inherited(child)
      puts "O2: BEFORE WITHOUT"
      inherited_without_o2(child)
      puts "O2: AFTER WITHOUT"
      puts "O2: #{child.inspect}"
    end
  end
end

class Override
  include O1
  include O2
end

class Child1 < Override
end

class Child2 < Child1
end

class Child3 < Override
end

---< snip >---

This prints:

Including O1 into Override
Including O2 into Override
O1: BEFORE WITHOUT
O1: AFTER WITHOUT
O1: Child1
O1: BEFORE WITHOUT
O1: AFTER WITHOUT
O1: Child2
O1: BEFORE WITHOUT
O1: AFTER WITHOUT
O1: Child3

If I instead modify O2 to use the same approach as O1, I get the
expected output:

Including O1 into Override
Including O2 into Override
O2: BEFORE WITHOUT
O1: BEFORE WITHOUT
O1: AFTER WITHOUT
O1: Child1
O2: AFTER WITHOUT
O2: Child1
O2: BEFORE WITHOUT
O1: BEFORE WITHOUT
O1: AFTER WITHOUT
O1: Child2
O2: AFTER WITHOUT
O2: Child2
O2: BEFORE WITHOUT
O1: BEFORE WITHOUT
O1: AFTER WITHOUT
O1: Child3
O2: AFTER WITHOUT
O2: Child3

Why would using an alias to create the new "inherited" work, but a
"def inherited" not?

Help much appreciated..
Leon

I guess it's this: the alias approach modifies method inherited of class Override directly. But when you extend Override by O2, Override's inherited shadows O2's inherited - so it's never called as there is no super call.

I'm not sure what exactly you want to achieve but maybe you are trying to do more than necessary: if a class instance is extended by a module, sub class instances inherit methods from the module automatically:

module Mod
  def bar() "bar" end
end

=> nil

class Base
  extend Mod
end

=> Base

Base.bar

=> "bar"

class Sub < Base
end

=> nil

Sub.bar

=> "bar"

Kind regards

    robert

···

leon breedt <bitserf@gmail.com> wrote:

It is my understanding that 'alias' doesn't behave in the sense that
it creates two method names that reference the same definition. Instead
it creates a new method and duplicates the definition of the old message.
The resulting method is completely independent of the original method.

Maybe I'm missing something (probably) but there seems to be a semantic
mismatch between the word 'alias' and the behavior of the method 'alias'.

Shouldn't it be called dup_method or something similar?

P.S. I had similar confusion with 'include' because of my C background.
I just couldn't get it into my head that 'include' was not attempting
to read some file somewhere. Once I figured that out, the relationship
between 'require' and 'include' was much more clear.

Gary Wright

···

On Jun 25, 2005, at 7:33 AM, leon breedt wrote:

I'm not exactly sure why defining a method with "def methodname"
versus aliasing it would behave differently.

Aha, this explanation, and Mauricio's, clears it up completely. Thanks!

Leon

···

On 6/26/05, Robert Klemme <bob.news@gmx.net> wrote:

leon breedt <bitserf@gmail.com> wrote:
I guess it's this: the alias approach modifies method inherited of class
Override directly. But when you extend Override by O2, Override's inherited
shadows O2's inherited - so it's never called as there is no super call.

Hi --

I'm not exactly sure why defining a method with "def methodname"
versus aliasing it would behave differently.

It is my understanding that 'alias' doesn't behave in the sense that
it creates two method names that reference the same definition. Instead
it creates a new method and duplicates the definition of the old message.
The resulting method is completely independent of the original method.

Maybe I'm missing something (probably) but there seems to be a semantic
mismatch between the word 'alias' and the behavior of the method 'alias'.

Shouldn't it be called dup_method or something similar?

I believe it's the other way around: aliasing a method name just adds
another name for the same method. If you then redefine the original
method, the two names then point to different methods:

   class C
     def x; end
     alias :y :x # y and x are the same method
     def x; "new method"; end # they are not the same
   end

At least that's always been my understanding of it.

David

···

On Sun, 26 Jun 2005 gwtmp01@mac.com wrote:

On Jun 25, 2005, at 7:33 AM, leon breedt wrote:

--
David A. Black
dblack@wobblini.net

David A. Black wrote:

I believe it's the other way around: aliasing a method name just adds
another name for the same method. If you then redefine the original
method, the two names then point to different methods:

  class C
    def x; end
    alias :y :x # y and x are the same method
    def x; "new method"; end # they are not the same
  end

At least that's always been my understanding of it.

I thought you were correct, and irb agrees:

irb(main):001:0> class C
irb(main):002:1> def a;puts 'a';end
irb(main):003:1> alias :b :a
irb(main):004:1> end
=> nil
irb(main):005:0> c = C.new
=> #<C:0x2b60238>
irb(main):006:0> c.a
a
=> nil
irb(main):007:0> c.b
a
=> nil
irb(main):008:0> ma = c.method(:a)
=> #<Method: C#a>
irb(main):009:0> mb = c.method(:b)
=> #<Method: C#b>
irb(main):010:0> ma.call
a
=> nil
irb(main):011:0> mb.call
a
=> nil
irb(main):012:0> ma == mb
=> true
irb(main):013:0> ms = c.method(:to_s)
=> #<Method: C(Kernel)#to_s>
irb(main):014:0> ms.call
=> "#<C:0x2b60238>"
irb(main):015:0> ms == ma
=> false
irb(main):016:0> class C
irb(main):017:1> def b;puts 'b';end
irb(main):018:1> end
=> nil
irb(main):019:0> c.b
b
=> nil
irb(main):020:0> ma == mb
=> true
irb(main):021:0> mb = c.method(:b)
=> #<Method: C#b>
irb(main):022:0> ma == mb
=> false

Ryan

Like I said, I was probably missing something. What I was missing was
a correct understanding of how method redefinition occurs. I was
thinking of method redefinition as an operation applied to the *existing*
method body. Sort of like changing the contents of a string. The
change is "visible" to anybody holding a reference to the string.

If I'm understanding correctly now, during method redefinition Ruby
constructs a brand new method body and then binds it to the existing
name thus breaking the binding made by the previous definition. If there
are multiple bindings to the same method body (via alias) then those old
bindings still have access to the original method body.

Thanks for the clarification.

Gary Wright

···

On Jun 26, 2005, at 3:56 PM, David A. Black wrote:

Maybe I'm missing something (probably) but there seems to be a semantic
mismatch between the word 'alias' and the behavior of the method 'alias'.

Shouldn't it be called dup_method or something similar?

I believe it's the other way around: aliasing a method name just adds
another name for the same method. If you then redefine the original
method, the two names then point to different methods:

gwtmp01@mac.com wrote:

If I'm understanding correctly now, during method redefinition Ruby
constructs a brand new method body and then binds it to the existing
name thus breaking the binding made by the previous definition. If there
are multiple bindings to the same method body (via alias) then those old
bindings still have access to the original method body.

Correct. In addition, as shown in my last email, any Method objects created to reference the old method will still reference it, even after a redefinition.

Ryan