In Ruby are there any related applications of the syntax: class << self ... end
Asked Answered
I

3

11
class << self
attr_accessor :n, :totalX, :totalY
end

The syntax above is used for defining class instance variables. But when I think about what syntax implies, it doesn't make any sense to me, so I'm wondering if this type of syntax is used for any other types of definitions. My point of confusion here is this:

class << self

The append operator normally means "add what's on the right to the object on the left". But in the context of this block, how does that add up to "put the contents of this block into the definition of the class instance rather than the instance"?

For the same reason I'm confused as to why in one context class << self can define class instance variables while in another it seems to create class variables such as here:

class Point
  # Instance methods go here
  class << self
    # Class methods go here
  end
end
Isaiasisak answered 22/5, 2009 at 5:30 Comment(0)
H
19

in Ruby you can reopen existing classes and add methods. That is, you can say:

class Foo
  def bob
    return "hello from bob"
  end
end

these methods get stored somewhere in an internal dictionary (maybe an instance variable) of the Foo-class (which is just an instance of the Class-class and therefore has instance variables)

But the suprising thing is, that you can also add methods to instances of existing objects

foo = Foo.new
foo2 = Foo.new

def foo.fred
  return "I am fred"
end


foo.fred  #=> "I am fred"
foo2.fred #=> NoMethodError

but Where is this method actually stored?

Turns out Ruby creates a new class behind the scenes (sometimes called singleton class, metaclass or eigenclass) which gets inserted in the inheritance heirarchy between the Foo-class and its instance.

So the inheritance relationship looks like that:

foo < (eigenclass of foo) < Foo < Class

(if you say foo.superclass you will not see the singleton class)

the class << X-syntax is a way to get to this special class, so that you can manipulate it directly. The following code blocks are exactly equivalent:

def foo.bar
  return "xy"
end

# is exactly the same as

class << foo
  def bar
    return "xy"
  end
end

So the similarity between class Foo < Bar and class << Foo is not accidental, there is inheritance going on in both.

Think of class << X as "open up the metaclass of X"

The thing to remember in Ruby is that classes themselves are just objects. (Instances of the class Class) so if you say:

class Foo
  class << self
    def k
      return "x"
    end
  end
end

(self is bound to Foo in this code block) so k is an instance method of the eigenclass of Foo, which makes it a class method for Foo

all this is explained more clearly in the chapter about classes of the Pickaxe (the web version does not contain the diagrams, unfortunately) and _whys Seeing Metaclasses Clearly

Hurless answered 22/5, 2009 at 10:19 Comment(0)
S
2

Think of the class as containing a dictionary of members including all the accessors and instance variables. When you tell the class to "append" to "itself", you're saying "add these to the dictionary of class members."

I'll grant the notation is a little hinky, though.

Shangrila answered 22/5, 2009 at 5:35 Comment(4)
Ok - that's a good way of looking at - the class is actually a dictionary. But actually you answered before I added my last example where in another context the same sytax (according to the book I'm reading) produces class methods instead of class instance methods. Why does the Point class example at the bottom result in a class method while the attr_accessor at the top gives you attributes that are at the class-instance level?Isaiasisak
Actually using the explanation you gave maybe I can answer the question in my previous comment - the attr_accessor method calls the Class class's instance_variable_set and instance_variable_get methods. Normally those would result in instance variables being created but because we are adding to the class dictionary, as you put it, we are creating class instance variables. Ok, I think I've got it now. Thanks.Isaiasisak
-1 misleading, since class << x ... end actually adds information to the metaclass of x, not the class of x.Lolanthe
Because, of course, adding information to the metaclass defining the class isn't actually adding things to the class, but to the metaclass that defines the class, thereby changing the class. Yah.Shangrila
S
1

it's actually confusing to think of it in terms of an "append" operator. a better way to look at it is that just as class Foo opens up class Foo, that is, it sets 'self' to the class object Foo, creating it if necessary, so class << self opens up the eigenclass of the current 'self' object. note that it is not limited to self - for any object bar, you can say class << bar to open up the eigenclass of that object.

class A
  def hello
    print "hello world"
  end
end

a = A.new
b = A.new

class << a
  def goodbye
    print "goodbye cruel world"
  end
end

a.hello
b.hello
a.goodbye
b.goodbye
Spirituel answered 22/5, 2009 at 6:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.