Why is self not the same as MyClass inside of the class << self scope.
Because the class keyword always changes the scope:
class MyClass
puts self #=> MyClass
class <<self
puts self #=>MyClass’s singleton class
end
end
More specifically, why is the method delegate not available to self
inside of class << self?
class MyClass
def self.delegate
puts "executing MyClass.delegate()"
end
class <<self
delegate
end
end
--output:--
1.rb:8:in `singleton class': undefined local variable or method `delegate' for #<Class:MyClass> (NameError)
from 1.rb:7:in `<class:MyClass>'
from 1.rb:1:in `<main>'
Note that the following constructs are equivalent:
class MyClass
def self.delegate
puts "executing MyClass.delegate()"
end
end
MyClass.delegate
--output:--
executing MyClass.delegate()
and:
class MyClass
class <<self
def delegate
puts "executing MyClass.delegate()"
end
end
end
MyClass.delegate
--output:--
executing MyClass.delegate()
Therefore, your code is equivalent to:
class MyClass
class <<self
def delegate
puts "executing MyClass.delegate()"
end
delegate
end
end
If you ignore the outer MyClass for a moment, then you defined a class like this:
class <<self
def delegate
puts "executing MyClass.delegate()"
end
delegate
end
That same structure can be replicated like this:
class Dog
def bark
puts “woof”
end
bark
end
which will produce the same type of error:
1.rb:7:in `<class:Dog>': undefined local variable or method `bark' for Dog:Class (NameError)
from 1.rb:1:in `<main>'
When you call a method and you don't specify a receiver, ruby uses whatever object is currently assigned to the self variable as the receiver.
Inside a method, ruby assigns the object that called the method to the self variable. The object that called the method is not the same thing as the class (object) in which the method is defined.
Inside a class, but outside of any method definitions, ruby assigns the class (object) to self.
Note that it is the instances of the Dog class that can call the def's inside the Dog class, e.g. bark(). Similarly, it is the instances of the singleton class that can call the def's inside the singleton class, e.g. delegate()--the singleton class itself cannot call the def's inside the singleton class. The whole reason they are called singleton classes is because singleton classes have only one instance--in your case the one instance of the singleton class is MyClass. As a result, MyClass can call delegate(), but the singleton class cannot call delegate().
I don't understand really what a class method on an eignclass is
however.
Personally, I don't use the term eigenclass
. In my opinion, ruby has made a decision that the term is singleton class
. If you look through the docs for the Object class, there are no method names that have eigenclass
in them, yet there are method names with singleton class
in them.
All objects have a singleton class. A singleton class is an object. Therefore, every singleton class also has a singleton class--which means that the chain of singleton classes is infinite:
class Dog
end
s1 = Dog.singleton_class
puts s1
s2 = s1.singleton_class
puts s2
s3 = s2.singleton_class
puts s3
--output:--
#<Class:Dog>
#<Class:#<Class:Dog>>
#<Class:#<Class:#<Class:Dog>>>
Which means you can do stuff like this:
class Dog
class <<self #s1
class <<self #s2
def greet #Instances of s2 can call greet, and the only instance of s2 is s1.
puts "hello"
end
end
end
end
class Dog
class <<self
#Inside here self = Dog's singleton class = s1
greet #equivalent to Dogs_singleton_class.greet
end
end
--output:--
hello
However, I've never seen anyone use a singleton class of a singleton class (s2) before in their code. I did it once to answer a question a long, long time ago, and nobody had any idea what I was talking about.
There are some method lookup diagrams here, which might prove useful.