views:

199

answers:

3
module M

  def f=(x)
    @f= x
  end

  def f
    @f
  end

end

class A
  extend M
end

class B < A
end

A.f= 42
puts A.f
puts B.f

this produces

42
nil

Is @f a class variable to A and B? How do I share a variable between A and B by only writing this into M?

A: 

Class variables may do what you need here:

module M

  def f=(x)
    @@f= x
  end

  def f
    @@f
  end

end

class A
  extend M
end

class B < A
end

A.f= 42
puts A.f
puts B.f

This produces:

42
42

This seems to be closer to the behavior you want:

def M()
  m = Module.new
  m.module_eval <<-HERE
    def f=(x)
      @@f= x
    end

    def f
      @@f
    end
  HERE
  m
end

class A
  extend M()
end

class B < A
end

class C
  extend M()
end


A.f= 42
puts A.f
puts B.f

C.f = 23
puts C.f
puts A.f
puts B.f

Produces:

 42
 42
 23
 42
 42
Logan Capaldo
The class variable now belongs to M and not to A or B, so it shared by all classes which are extended. But it should only be shared by all subclasses and the class itself module M @@f= nil def f=(x) @@f= x end def f @@f end end class A extend M end class C extend M end A.f= 42 C.f= 23 puts A.f puts C.fproduces 23 23
johannes
If you want to share data between (sub)classes like this, it's going to have to be through either a) class variables or b) trickier with hooks. An instance variable (single `@`) is never a class variable, no matter from whose perspective (they live in different places and have different scopes).
Logan Capaldo
But how do I get a class variable of A by extending it with M.Your solution creates a class variable of M and not A.
johannes
Some variety of eval is going to be the only way. Is the "must use extend" a hard and fast rule?
Logan Capaldo
I want to make it a module so it can used in different classes. Extend or include are the standard way to extend classes, I'd rather use one of this, than doing some ugly stuff.
johannes
I think class_variable_set and class_variable_get, is a much clener way, than creating a seperate module with seperate methods for each class it's included. Evaluating strings where there is no need to, is also ugly.
johannes
Sounds like you already know the answer. Why ask the question then?
Logan Capaldo
I didn't knew the answer at the time I asked. You helped me with your input to find it.
johannes
A: 

B::A.f will produce the correct result

ennuikiller
warning: toplevel constant A referenced by B::A
johannes
A: 

By not using @@f directly, but rather class_variable_set() and class_variable_get(), class variables of A, B and C can be used from within M.

module M

    def f=(x)
     class_variable_set("@@f", x)
    end

    def f
     class_variable_get("@@f")
    end

end

class A
    extend M
end

class B < A
end

class C
    extend M
end

A.f= 42
C.f= 23
puts A.f
puts B.f
puts C.f

this produces

42
42
23

As you can see, the variables are shared by A and B, but not C.

johannes