2
class A
  def set(v)
    @@v = v
  end
  def put
    puts @@v
  end
end

class B < A
end
class C < A
end

B.new.set 'b'
B.new.put # => b
C.new.set 'c'
C.new.put # => c
B.new.put # => c

Why? And how should I write this to have 'b' in last B.new.put?

1
  • Are you sure you don't just want instance variables? (e.g. @v, instead of @@v) Commented Dec 3, 2011 at 17:33

3 Answers 3

5

Here is a nice article on the subject - Class and Instance Variables In Ruby.

Basically, what you can do is:

class A
  class << self
    attr_accessor :class_var
  end

  def set_class_var(value)
    self.class.class_var = value
  end

  def get_class_var
    self.class.class_var
  end
end

class B < A; end

A.class_var = 'a'
B.class_var = 'b'
puts A.class_var # => a
puts B.class_var # => b

A.new.set_class_var 'aa'
B.new.set_class_var 'bb'
puts A.new.get_class_var # => aa
puts B.new.get_class_var # => bb

To understand it you should think about A as an instance of Class class (and that's how it is in Ruby). But every object in Ruby has its own singleton class that stores object-specific stuff like methods defined on object itself:

a = A.new
def a.foo
  puts 'foo'
end

In that case foo is method defined only for a object and not for every instance of A class. And another way to define method in object's singleton class is like that:

class << a # open a's singleton class
  def bar  # define method that will be available only on 'a' object
    puts 'bar'
  end
end

In the first code snippet we use that approach to define class_var attribute accessor in the context of singleton class of our A class (it's a bit tricky, so you need to think about it). As the result class itself has class_var variable as well as its descendant class B. The difference is that every one of them has its own class_var variable that do not interfere.

Sign up to request clarification or add additional context in comments.

Comments

2

Another option is to pull out class_inheritable_accessor code from Rails and include its behavior in your classes. See here for a good discussion and the guts of the code.

Perhaps you don't really want a class variable, though.

1 Comment

@Ximik No problem. It's basically an extensible, hierarchical version of KL-7's answer;
-1

Assigning a value to a class variable (an @@ variable) sets it for EVERY instance of the class. It even "sets" it for instances that "aren't created yet." So, consider this...

B.new.set 'b' # OK, that set @@v for that particular instance of B

B.new.put # Hey, you just created *another* new instance of B!  

How can @@v have a value in that one? The second object's value of @@v would be unset, except for the fact that @@v is a class variable, so it has the same value for every instance of the class.

1 Comment

The real problem here is that class variable in Ruby is actually class-hierarchy variable. The class shares his class variables with all his descendants.

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.