-3

How should I consider a @variable declared within the class << self block outside any method definition? Look at the final part of this script:

class VarDemo
  @@class_var_1 = "This is @@class_var_1"
  @class_i_var = "This is a @class_i_var"

  attr_accessor :ivar_1
  attr_accessor :ivar_2

  def initialize(ivar_1: "base_ivar_1", ivar_2: "base_ivar_2")
    @@class_var_2 = "This is @@class_var_2, defined within an instance method"
    @ivar_1 = ivar_1
    @ivar_2 = ivar_2
    VarDemo.class_i_var_2 = "class_i_var_2 defined through accessor on the class object"
  end

  def print_vars
    puts "from within an instance method. here 'self' is: #{self}"

    # test instance variables
    puts "@ivar_1: #{@ivar_1}"
    puts "@ivar_2: #{@ivar_2}"
    puts "self.ivar_1: #{self.ivar_1}"
    puts "self.ivar_2: #{self.ivar_2}"
    puts "ivar_1: #{ivar_1}"
    puts "ivar_2: #{ivar_2}"

    # test class variables
    puts "@@class_var_1: #{@@class_var_1}"
    puts "@@class_var_2: #{@@class_var_2}"

    # test class instance variables (ivars on the class object)
    puts "VarDemo.class_i_var: #{VarDemo.class_i_var}"
    puts "VarDemo.class_i_var_2: #{VarDemo.class_i_var_2}"
    puts "@class_i_var: #{@class_i_var} (should be empty, as it doesn't exist in the instance"

    puts "self.class_i_var: #{self.class_i_var}"
  rescue Exception => ex
    puts "self.class_i_var is not defined in this scope (self is an instance)"
  end

  # open the class object
  class << self
    attr_accessor :class_i_var
    attr_accessor :class_i_var_2

    @what_about_this = "what would this be?"

    attr_accessor :what_about_this

    def print_what_about_this
      puts "@what_about_this: #{@what_about_this}" # is empty
      puts "VarDemo.what_about_this: #{VarDemo.what_about_this}" # is empty
    end
  end

end

What is @what_about_this? Where is it defined? Is it just something that the interpreter lets me do, but without any practical use? I thought it was defined on Class, but that doesn't appear to be the case.

Senjai
  • 1,811
  • 3
  • 20
  • 40
tompave
  • 11,952
  • 7
  • 37
  • 63
  • [Don’t rescue from Exception—ever!](http://stackoverflow.com/q/10048173/211563) – Andrew Marshall May 13 '13 at 00:13
  • Hi Andrew. Thanks for the link! I already knew that rescuing from the root `Exception` was bad for some reasons (blocking unix signals), and in "real use" code I usually adopt a more fine-grained control on errors... but the answer you linked is very useful indeed. I wasn't aware of the `eval` issue... good to know. – tompave May 13 '13 at 12:13
  • Doing it in non-“real-use” code only makes it more likely to accidentally do it in “real” code, or forget to change it later. – Andrew Marshall May 13 '13 at 22:53

1 Answers1

2

The class <<self doesn't actually open up self's class; it opens up self's singleton class. (Described here.)

class Foo
  class << self
    @bar = "baz"   # not really inside Class here.
  end
end

Foo.singleton_class.instance_eval { @bar }  #baz

Yehuda Katz has a good article that describes what's really going on here.

Mark Reed
  • 91,912
  • 16
  • 138
  • 175
  • yes, I know. It opens the singleton class of whatever `self` refers to in the current scope. If used within a class (MyClass) body, `self` is equivalent to `MyClass`. Any class (`String`, `MyClass`, ecc) is just an instance of the `Class` class, and that's way you can declare class instance variables on classes... because they are objects too. – tompave May 12 '13 at 23:16
  • Anyway, any idea about that `@what_about_this` variable? – tompave May 12 '13 at 23:19
  • You asked where the instance variable went. I told you - it's on your class's singleton class (a.k.a. its eigenclass), which is *not* the same as `Class` itself. – Mark Reed May 12 '13 at 23:20
  • `VarDemo.singleton_class.instance_eval { @what_about_this }` Voilà! – Mark Reed May 12 '13 at 23:21
  • Thanks Mark. Katz's link was very useful. – tompave May 13 '13 at 12:15