7

I have the following piece of code:

class Fish
# @message = "I can swim"

 class << self
  @message = "I can jump!"
  define_method(:action) { @message }
 end
end


Fish.action  => nil

As soon as I uncomment the above @message variable, Fish.action returns I can swim. Why in both cases it is ignoring the I can jump message. Why is that? Why is Fish class being binded to the @message defined at the start but not inside the singleton class?

1
  • This is oh-so-close to this question just asked a few minutes ago. If you move the definition of the class method action outside the singleton class and define it (equivalently) def self.action; @message; end, the answers to the earlier question would apply to your question as well. Commented Oct 24, 2016 at 6:10

1 Answer 1

6

It's because class << self opens the class' singleton class context:

class Foo
  p self # Foo
  class << self
    p self # #<Class:Foo>
    define_method(:bar) { p self } # Foo
  end
end
Foo.bar

You can verify that by:

Fish.singleton_class.instance_variable_get(:@action) # => "I can jump!"
Sign up to request clarification or add additional context in comments.

6 Comments

Can we say "class << self changes self to Foo's singleton class"? It seems more precise to me. I know "open a class" is often used, but nowhere (as far as I know) does Ruby provide a definition for "opening" a class.
@CarySwoveland, this implies that only self changes, but the current class also changes (think of it like instance_eval vs class_eval).
I think we're saying the same thing, that self is changed to Foo.singleton_class between class << self and its end.
@CarySwoveland, I'm saying something more. "class << self changes self to Foo's singleton class" basically means class << self; _something_; end and singleton_class.instance_eval { _something_ } are equivalent (they are not). "Opens Foo's ' singleton class context" is the equivalent of singleton_class.class_eval { _something_ }
@mhaseeb, for the same reason given class Bar; p self; def baz; p self; end; end, the self outside the method will be Bar, but the self inside the method will be whatever instance you call it on. Methods are defined in classes, but act on the instances of said classes.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.