John Merlino
2012-Oct-06 19:43 UTC
more misleading content on the web regarding ruby method lookup algorithm
I read this article: http://www.madebydna.com/all/code/2011/06/24/eigenclasses-demystified.html Author makes claim that are flat out wrong. She says: "Class gets "pushed up" the lookup chain and becomes a superclass." That statement is flat out wrong. A class object does not inherit from class Class. In fact, if you try it you will get a TypeError. A class object is an instance of class Class. If a class object does not inherit from anything, then it implicitly inherits from class Object, which itself is an instance of class Class. What happens is as follows: First off, when a class (aka singleton) method is defined on class Dog, an eigenclass is created. For all intents and purposes, this eigenclass becomes the class of the Dog object. Class does not get "pushed up" the lookup chain. It''s the superclass that gets pushed up the lookup chain, which in this example, is Mammal. In other words, it will look at Dog''s eigenclass and if it doesn''t find it there, it will then look at Mammal''s eigenclass, and then Object (so its Object that continuously gets pushed back) and then BasicObject. Here''s an example that shows Class does not get pushed back, because the class object never even inherits the eigenclass of Class to begin with (the class object is simply an instance of Class): Loading development environment (Rails 3.1.2) 1.9.3p0 :001 > class Mammal 1.9.3p0 :002?> def Mammal.mammal_singleton 1.9.3p0 :003?> puts ''mammal singleton'' 1.9.3p0 :004?> end 1.9.3p0 :005?> end => nil 1.9.3p0 :006 > 1.9.3p0 :007 > class Dog < Mammal 1.9.3p0 :008?> def Dog.dog_singleton 1.9.3p0 :009?> puts ''dog singleton'' 1.9.3p0 :010?> end 1.9.3p0 :011?> end => nil 1.9.3p0 :012 > 1.9.3p0 :013 > class Object 1.9.3p0 :014?> def Object.object_singleton 1.9.3p0 :015?> puts ''object singleton'' 1.9.3p0 :016?> end 1.9.3p0 :017?> end => nil 1.9.3p0 :018 > 1.9.3p0 :019 > class Class 1.9.3p0 :020?> def Class.class_singleton 1.9.3p0 :021?> puts ''class singleton'' 1.9.3p0 :022?> end 1.9.3p0 :023?> end => nil 1.9.3p0 :024 > Dog.dog_singleton dog singleton => nil 1.9.3p0 :025 > Dog.mammal_singleton mammal singleton => nil 1.9.3p0 :026 > Dog.object_singleton object singleton => nil 1.9.3p0 :027 > Dog.class_singleton NoMethodError: undefined method `class_singleton'' for Dog:Class from (irb):27 #It fails because class Class is not in the eigenclass lookup chain of Dog class object, since class Class is not a superclass of Dog. However, by defining an instance method in class Class, then that will be able to be invoked on Dog, since Dog is an instance of class Class: 1.9.3p0 :028 > class Class 1.9.3p0 :029?> def class_instance 1.9.3p0 :030?> puts ''class instance'' 1.9.3p0 :031?> end 1.9.3p0 :032?> end => nil 1.9.3p0 :033 > Dog.class_instance class instance => nil So the real question is this, which that article obscured. If I invoke a method on Dog, will it search the Class hierarchy for an associated instance method first (and continue looking up the lookup algorithm for instance methods via Module, Object, and BasicObject which class Class inherits from) or will it search Dog''s eigenclass and its superclasses'' eigenclasses (all the way up to the eigenclass of Object and BasicObject) first? The proof is in the pudding: 1.9.3p0 :044 > class Object 1.9.3p0 :045?> def Object.sing_method 1.9.3p0 :046?> puts ''singleton method'' 1.9.3p0 :047?> end 1.9.3p0 :048?> def inst_method 1.9.3p0 :049?> puts ''instance method'' 1.9.3p0 :050?> end 1.9.3p0 :051?> end => nil 1.9.3p0 :052 > Dog.sing_method singleton method => nil 1.9.3p0 :053 > Dog.inst_method instance method => nil #as suspected, invocations on Dog lead to both eigenclass methods of Object and instance methods of Object, since Dog is an instance of class Class, and class Class inherits from Object via Module, and Dog at the same time inherits from Object (via inheritance), which is done implicitly by Ruby. Now which get invoked first, the instance methods or eigenclass methods? 1.9.3p0 :062 > class Object 1.9.3p0 :063?> def Object.method_lookup 1.9.3p0 :064?> puts ''eigenclass method called first!'' 1.9.3p0 :065?> end 1.9.3p0 :066?> def method_lookup 1.9.3p0 :067?> puts ''instance method is called first!'' 1.9.3p0 :068?> end 1.9.3p0 :069?> end => nil 1.9.3p0 :070 > Dog.method_lookup eigenclass method called first! => nil And there you have it, the method resolution algorithm looks up the singleton methods prior to the instance methods of a class object. -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org For more options, visit https://groups.google.com/groups/opt_out.
Bill Walton
2012-Oct-06 20:16 UTC
Re: more misleading content on the web regarding ruby method lookup algorithm
Hi John, On Sat, Oct 6, 2012 at 2:43 PM, John Merlino <stoicism1-YDxpq3io04c@public.gmane.org> wrote:> I read this article: > > http://www.madebydna.com/all/code/2011/06/24/eigenclasses-demystified.html > > Author makes claim that are flat out wrong. She says: "Class gets > "pushed up" the lookup chain and becomes a superclass." That statement > is flat out wrong. >Nice job. Just FYI, Dave Thomas did a Screencast series on Ruby MetaProgramming, the first of which covers this very clearly. I found it well worth the $5. Best regards, Bill -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org For more options, visit https://groups.google.com/groups/opt_out.