Reputation: 89576
I can't seem to grasp the exact difference between these two "constructs". To my mind, the following small script should output the same thing three times:
class Example
puts self
class << self
puts self
end
instance_eval do
puts self
end
end
However, the output is:
Example
#<Class:Example>
Example
Here's my rationale:
Example
is an instance of Class
, so self
in the class body refers to that;class << obj
sets self
to whatever obj
is in the given block, which in my case is the instance of Class
that is Example
(this is where I'm probably wrong);instance_eval
runs the block in the given instance, so, in my case it's pretty much the same as putting the code in the block directly in the class body.My current guess is that class << self
inserts a ghost class between Example
and Class
and sets self to that, but the output of #<Class:Example>
is not confirming that at all.
So what is wrong with my rationale?
Upvotes: 4
Views: 559
Reputation: 211590
In my opinion, class << self
has been one of the most obnoxious bits of syntax in Ruby. People new to the language have little idea what it means, apart from cargo-cult conventions, and even those intimately familiar with the language have only a hazy understanding of what differentiates it from instance_method
, as the two do seem to be remarkably similar.
Here's an example of two different ways of defining a class method:
class Example
class << self
def class_def
:class_def
end
end
instance_eval do
def instance_def
:instance_def
end
end
end
You can check that these work by calling the methods:
puts Example.class_def.inspect
# => :class_def
puts Example.instance_def.inspect
# => :instance_def
The difference is when you're dynamically creating methods using define_method
since the binding does appear to be incorrect on the instance_eval
version:
class Example
class << self
define_method(:class_def) do
:class_def
end
end
instance_eval do
define_method(:instance_def) do
:instance_def
end
end
end
This results in the instance_def
method being defined, but not being bound to the class itself:
puts Example.class_def.inspect
# => :class_def
puts Example.instance_def.inspect
# => NoMethodError: undefined method ‘instance_def’ for Example:Class
The only reliable way to create dynamic methods is with class << self
. The method instance_def
appears to be created and discarded as it doesn't show up in Example.methods even inside that block.
Upvotes: 3
Reputation: 369458
class << obj
setsself
to whateverobj
is in the given block, which in my case is the instance ofClass
that isExample
(this is where I'm probably wrong);
No, class << obj
opens up the singleton class of obj
. As you correctly pointed out, inside of a class declaration, self
refers to the class itself, so, in this case, the "inner" self
(i.e. the one being passed to puts
) refers to the singleton class of Example
.
Upvotes: 6