Class attribute unique to subclasses but used in parent class

Hello,

I'm new in the Ruby World and I have a question.

Let's say I have a class with a class attribute (I call this class
Parent), this class attribute is used in instance methods of Parent.
Parent class has many subsclasses. Each subsclass should have it's own
value of the class attribute.

Example:

class Parent
  @@test = nil

  def Parent.create(value)
    @@test=value
    new
  end

  def print_test
    puts @@test
  end
end

class Child1 < Parent
end

class Child2 < Parent
end

c1 = Parent.create '1'
c1.print_test # => 1
c2 = Parent.create '2'
c2.print_test # => 2
c1.print_test # => 2

What I'll like, is that Child1 and Child2 have their own values of
@@test, but @@test should be initialized and used in Parent.
Also, @@test cannot be an instance variable because it is heavy to
initialize and will be common to all instances of Child1 or Child2.

Thank you

Hi --

Hello,

I'm new in the Ruby World and I have a question.

Let's say I have a class with a class attribute (I call this class
Parent), this class attribute is used in instance methods of Parent.
Parent class has many subsclasses. Each subsclass should have it's own
value of the class attribute.

Example:

class Parent
@@test = nil

def Parent.create(value)
   @@test=value
   new
end

def print_test
   puts @@test
end
end

class Child1 < Parent
end

class Child2 < Parent
end

c1 = Parent.create '1'
c1.print_test # => 1
c2 = Parent.create '2'
c2.print_test # => 2
c1.print_test # => 2

What I'll like, is that Child1 and Child2 have their own values of
@@test, but @@test should be initialized and used in Parent.
Also, @@test cannot be an instance variable because it is heavy to
initialize and will be common to all instances of Child1 or Child2.

Actually it should be an instance variable, but an instance variable
of the class object.

What you're trying to do is to maintain state on a per-object basis,
and for that you need an instance variable. In fact, you can give
your class objects their own accessor methods, by creating those
methods in the singleton class of the first one:

class C
   class << self
     attr_accessor :n
   end
end

class D < C
end

C.n = 1
p C.n # 1
D.n = 2
p D.n # 2
p C.n # 1

Note that if you do this, you have to use the accessor methods to get
at the values from outside (as is the case with all objects):

   class C
     def my_class_n
       self.class.n
     end
   end

   c = C.new
   C.n = 100
   puts c.my_class_n # 100

But that's actually good. Since the object (C) is maintaining its own
state, it makes perfect sense to have to query it. Class variables
demolish that logic, which is one of a number of reasons I dislike
them.

David

···

On Sat, 28 Oct 2006, lcor1979@gmail.com wrote:

--
                   David A. Black | dblack@wobblini.net
Author of "Ruby for Rails" [1] | Ruby/Rails training & consultancy [3]
DABlog (DAB's Weblog) [2] | Co-director, Ruby Central, Inc. [4]
[1] Ruby for Rails | [3] http://www.rubypowerandlight.com
[2] http://dablog.rubypal.com | [4] http://www.rubycentral.org

lcor1979@gmail.com wrote:

What I'll like, is that Child1 and Child2 have their own values of
@@test, but @@test should be initialized and used in Parent.
Also, @@test cannot be an instance variable because it is heavy to
initialize and will be common to all instances of Child1 or Child2.

Class variables and class instance variables sound way too much like
global state coming into the system through a backdoor, I'd avoid both.

Personally, I'd replace lookup through a class variable or class
instance variable with injecting the shared object into instances. The
less shared state, the more flexibility you gain in being able to rewire
your objects.

Disclaimer: I am biased in favour of IoC and DI based "objects floating
in vacuum" designs, especially for scenarios that involve reusing an
expensive-to-create component like this one. If nothing else,
declarative dependency resolution lets you plug in testing components
easier / clearer than imperative (even if Ruby makes the latter easier
in that you're allowed to molest any object in arbitrary ways.)

David Vallner

Hi --

···

On Sun, 29 Oct 2006, David Vallner wrote:

lcor1979@gmail.com wrote:

What I'll like, is that Child1 and Child2 have their own values of
@@test, but @@test should be initialized and used in Parent.
Also, @@test cannot be an instance variable because it is heavy to
initialize and will be common to all instances of Child1 or Child2.

Class variables and class instance variables sound way too much like
global state coming into the system through a backdoor, I'd avoid both.

Personally, I'd replace lookup through a class variable or class
instance variable with injecting the shared object into instances. The
less shared state, the more flexibility you gain in being able to rewire
your objects.

Instance variables don't involve shared state, though; they're
strictly per object (Class object or otherwise).

David

--
                   David A. Black | dblack@wobblini.net
Author of "Ruby for Rails" [1] | Ruby/Rails training & consultancy [3]
DABlog (DAB's Weblog) [2] | Co-director, Ruby Central, Inc. [4]
[1] Ruby for Rails | [3] http://www.rubypowerandlight.com
[2] http://dablog.rubypal.com | [4] http://www.rubycentral.org