-1

In Ruby, What is the difference between @@variable to self.variable

  1. In the scope of main.

  2. In the scope of the class

  3. In the scope of a method

For example my file looks like:

self.variable = 'data'
@@variable = 'data'

def class A
  self.variable = 'data'
  @@variable = 'data'

  def method()
    self.variable = 'data'
    @@variable = 'data'
  end
end

How many variables are there? And under what scope?

iceveda06
  • 601
  • 8
  • 21
Dolev
  • 654
  • 11
  • 20
  • 1
    https://stackoverflow.com/questions/3802540/difference-between-class-variables-and-class-instance-variables ? – Mr. Alien Apr 04 '18 at 11:09
  • @Mr.Alien Good related read. But it doesn't cover the question – Dolev Apr 04 '18 at 11:13
  • Possible duplicate of [Difference between class variables and class instance variables?](https://stackoverflow.com/questions/3802540/difference-between-class-variables-and-class-instance-variables) – jdno Apr 04 '18 at 11:18
  • 2
    Can you provide a bit more context in your question then, and also explain why the one linked by @Mr.Alien doesn't answer it? – jdno Apr 04 '18 at 11:25
  • @jdno Does that change provide more context? – Dolev Apr 04 '18 at 11:30
  • 4
    For the given code, each `self.variable =` results in a `NoMethodError`. – Stefan Apr 04 '18 at 11:38

2 Answers2

4
self.variable = 'data'

This is a method call at toplevel. The self. just distinguishes it as a method call versus a local variable definition. Assuming you have def variable= x somewhere, it will call that method. Otherwise it's a NoMethodError

@@variable = 'data'

This generates a warning: "class variable access from toplevel". Class variables are shared among all objects of that class and subclasses. Toplevel's class is just Object, so effectively this is a global class variable [].instance_eval { @@variable } # 'data' because everything ultimately derives from Object.

def class A
  self.variable = 'data'
  @@variable = 'data'

Same deal as above, but now the receiver is A so it will call A.variable=('data') and set @@variable on A.

  def method()
    self.variable = 'data'
    @@variable = 'data'

And now the receiver is some instance of A, let's say a = A.new. So it's a.variable=('data'). @@variable is set for A as before since all instances of a class (and its subclasses) share the one variable.

The only case in which you can assume that self.variable = 'data' means anything in particular is if you see attr_accessor :variable or attr_writer :variable in the class's context. In those cases it's a particular method call that sets @variable. Otherwise it could do literally anything and you need to read the method definition.

Max
  • 21,123
  • 5
  • 49
  • 71
1
  1. Difference between @@variable and self.variable in scope of main.

As we probably know, @@variable is a class variable.

@@variable will attach itself to the class of self.class. The class of main is Object.

To demonstrate:

self # => main
self.class # => Object
@@variable = "variable"
self.class.class_variables # => [:@@variable]
object.class_variables # => [:@@variable]

Be aware, this means every object will have access to @@variable.

String.class_variables # => [:@@variable]

and modifying that variable at the top level will also change its value for all objects.

self.variable will give a NoMethodError, as there are no getters or setters for it. If you were to define a getter and setter, however ...

class Object
  class << self
    attr_accessor :variable
  end
end
self.variable = "variable" # => "variable"
  1. Difference between @@variable and self.variable in scope of a class.

@@variable will be have the same way as above, except now instead of class Object, we're applying it to whatever class we're currently in.

But now, self.variable will apply to a Class Instance Variable. This is the sort of variable that's most commonly referred to as Class Variables or Static Variables in other languages (ie. it is only accessible to that class, and not its children). It is the same as having a @variable at the class's top level.

class T
  @some = "some"
  class << self
    attr_accessor :variable
  end
  self.variable = "variable"
end
T.instance_variables # => [:@some, :@variable]
  1. Difference between @@variable and self.variable in scope of a method.

@@variable behaves exactly as above -- it's still referring to the class we are defining the method of.

But now self.variable refers to an instance variable, not the Class's instance.

class T
  attr_accessor :variable
  def initialize
    self.variable = "variable"
  end
end
instance = T.new
instance.instance_variables
instance.variable # => "variable"
  1. "How many variables are there? And under what scope?"

In your example, there are 5 variables (assuming proper getters/setters have been created):

  1. Class variable @@variable belonging to Object
  2. Instance variable main.variable belonging to the instance main of class Object
  3. Class variable @@variable belonging to A
  4. Class Instance variable A.variable belonging to class A
  5. Instance variable @variable belonging to any instances of A.