[newby] class variables and class instance variable?

Discussion in 'Ruby' started by Lionel Thiry, Mar 12, 2005.

  1. Lionel Thiry

    Lionel Thiry Guest

    Hello.

    class Test
    @a = "value"

    def self.a
    @a
    end

    def initialize
    @@a = "value2"
    end

    def a
    @@a
    end
    end

    puts Test.a # output: value
    puts Test.new.a # output: value2

    I don't understand (and I'm quite surprised), what is the difference in terms of
    OO design between class variables, the @@a in the example above, and class
    instance variables, the @a in the example?

    Thanks in advance,
    Lionel Thiry
    Lionel Thiry, Mar 12, 2005
    #1
    1. Advertising

  2. Lionel Thiry wrote:

    > class Test
    > @a = "value"
    >
    > def self.a
    > @a
    > end
    >
    > def initialize
    > @@a = "value2"
    > end
    >
    > def a
    > @@a
    > end
    > end
    >
    > puts Test.a # output: value
    > puts Test.new.a # output: value2
    >
    > I don't understand (and I'm quite surprised), what is the difference in
    > terms of OO design between class variables, the @@a in the example
    > above, and class instance variables, the @a in the example?


    Currently class variables are also shared between different classes that
    are part of the same inheritance tree. IMHO this is a rarely needed
    feature and you're better off using regular instance variables on the
    class (and referring to them via self.class.var from an instance).
    Florian Gross, Mar 12, 2005
    #2
    1. Advertising

  3. Lionel Thiry

    Lionel Thiry Guest

    Florian Gross wrote:
    > Lionel Thiry wrote:


    >> I don't understand (and I'm quite surprised), what is the difference
    >> in terms of OO design between class variables, the @@a in the example
    >> above, and class instance variables, the @a in the example?

    >
    >
    > Currently class variables are also shared between different classes that
    > are part of the same inheritance tree.

    I ignored that. *doing some testing* My! You're right.

    > IMHO this is a rarely needed
    > feature and you're better off using regular instance variables on the
    > class (and referring to them via self.class.var from an instance).


    I totally agree.

    Thanks a lot,
    Lionel Thiry
    Lionel Thiry, Mar 12, 2005
    #3
  4. --
    Wolfgang Nádasi-Donner

    "Lionel Thiry" <> schrieb im Newsbeitrag
    news:4232ff57$0$30162$...
    > Hello.
    >
    > class Test
    > @a = "value"
    >
    > def self.a
    > @a
    > end
    >
    > def initialize
    > @@a = "value2"
    > end
    >
    > def a
    > @@a
    > end
    > end
    >
    > puts Test.a # output: value
    > puts Test.new.a # output: value2
    >
    > I don't understand (and I'm quite surprised), what is the difference in

    terms of
    > OO design between class variables, the @@a in the example above, and class
    > instance variables, the @a in the example?
    >
    > Thanks in advance,
    > Lionel Thiry


    The class variable ("@@") belongs to the class object, while the instance
    variable (@) belongs to the instanciated object. A short example. May be you
    want to count how many objects are created based on a class. If you want to
    avoid global variables ($), which is a very good decision, you can use class
    variables. Using instance variables will not work.

    >>>>> Example >>>>>

    class Mytest
    @@n_of_Mytest = 0
    def initialize
    @@n_of_Mytest += 1
    end
    def Mytest.n_of_Mytest
    @@n_of_Mytest
    end
    end

    puts Mytest.n_of_Mytest
    a = Mytest.new
    puts Mytest.n_of_Mytest
    b = Mytest.new
    c = Mytest.new
    puts Mytest.n_of_Mytest
    d = Mytest.new
    e = Mytest.new
    f = Mytest.new
    puts Mytest.n_of_Mytest
    >>>>> Output >>>>>

    0
    1
    3
    6
    >>>>> End of Example >>>>>


    O.K.?
    Wolfgang Nádasi-Donner, Mar 13, 2005
    #4
  5. Lionel Thiry

    ts Guest

    >>>>> "W" == Wolfgang Nádasi-Donner <> writes:

    >>>>> Example >>>>>

    W> class Mytest
    W> @@n_of_Mytest = 0

    svg% cat b.rb
    #!/usr/local/bin/ruby
    class Mytest
    @n_of_Mytest = 0

    def initialize
    self.class.instance_eval { @n_of_Mytest += 1}
    end

    def Mytest.n_of_Mytest
    @n_of_Mytest
    end
    end

    puts Mytest.n_of_Mytest
    a = Mytest.new
    puts Mytest.n_of_Mytest
    b = Mytest.new
    c = Mytest.new
    puts Mytest.n_of_Mytest
    d = Mytest.new
    e = Mytest.new
    f = Mytest.new
    puts Mytest.n_of_Mytest
    svg%

    svg% b.rb
    0
    1
    3
    6
    svg%




    --

    Guy Decoux
    ts, Mar 13, 2005
    #5
  6. Wolfgang Nádasi-Donner wrote:

    > The class variable ("@@") belongs to the class object, while the instance
    > variable (@) belongs to the instanciated object. A short example. May be you
    > want to count how many objects are created based on a class. If you want to
    > avoid global variables ($), which is a very good decision, you can use class
    > variables. Using instance variables will not work.


    It will. Note that the poster said "class instance variable" which is
    the instance variable of a Class. Classes are instances of Class and
    Class inherits from Module which inherits from Object so classes are
    objects as well:

    class Foo
    @counter = 0
    class << self
    attr_accessor :counter
    end

    def initialize()
    self.class.counter += 1
    end
    end

    Foo.counter # => 0
    5.times { Foo.new }
    Foo.counter # => 5
    Florian Gross, Mar 13, 2005
    #6
  7. --
    Wolfgang Nádasi-Donner

    "Florian Gross" <> schrieb im Newsbeitrag
    news:...
    > Wolfgang Nádasi-Donner wrote:
    >
    > > The class variable ("@@") belongs to the class object, while the

    instance
    > > variable (@) belongs to the instanciated object. A short example. May be

    you
    > > want to count how many objects are created based on a class. If you want

    to
    > > avoid global variables ($), which is a very good decision, you can use

    class
    > > variables. Using instance variables will not work.

    >
    > It will. Note that the poster said "class instance variable" which is


    *****************************************************
    Ooops - need new glasses, I believe ;-) - Forget my example, please.
    I often switch between Ruby an C#. This results in some confusion.
    *****************************************************

    > the instance variable of a Class. Classes are instances of Class and
    > Class inherits from Module which inherits from Object so classes are
    > objects as well:
    >
    > class Foo
    > @counter = 0
    > class << self
    > attr_accessor :counter
    > end
    >
    > def initialize()
    > self.class.counter += 1
    > end
    > end
    >
    > Foo.counter # => 0
    > 5.times { Foo.new }
    > Foo.counter # => 5
    Wolfgang Nádasi-Donner, Mar 13, 2005
    #7
  8. Lionel Thiry

    Lionel Thiry Guest

    >>>>>>Example >>>>>
    >
    > class Mytest
    > @@n_of_Mytest = 0
    > def initialize
    > @@n_of_Mytest += 1
    > end
    > def Mytest.n_of_Mytest
    > @@n_of_Mytest
    > end
    > end
    >
    > puts Mytest.n_of_Mytest
    > a = Mytest.new
    > puts Mytest.n_of_Mytest
    > b = Mytest.new
    > c = Mytest.new
    > puts Mytest.n_of_Mytest
    > d = Mytest.new
    > e = Mytest.new
    > f = Mytest.new
    > puts Mytest.n_of_Mytest
    >
    >>>>>>Output >>>>>

    >
    > 0
    > 1
    > 3
    > 6
    >
    >>>>>>End of Example >>>>>

    >
    >
    > O.K.?
    >
    >


    I've tested your code and I've been surprised that it actually worked. If I
    correctly understand the mechanism, it's like the class object and its instances
    are able to access class variables through '@@'. Undubitably, I know now why I
    couldn't get along with that feature.

    Honestly, I largely prefer to think of classes as objects and use the class
    instance variables when I want to share variables between instances. Using '@@'
    doesn't seem reliable for me, as IMHO it violates some important OO principles,
    the kind that if not followed leads to very embarrassing problems.

    Thanks for your help,
    Lionel Thiry
    Lionel Thiry, Mar 13, 2005
    #8
  9. --
    Wolfgang Nádasi-Donner

    "Florian Gross" <> schrieb im Newsbeitrag
    news:...
    > Lionel Thiry wrote:
    >
    > > class Test
    > > @a = "value"
    > >
    > > def self.a
    > > @a
    > > end
    > >
    > > def initialize
    > > @@a = "value2"
    > > end
    > >
    > > def a
    > > @@a
    > > end
    > > end
    > >
    > > puts Test.a # output: value
    > > puts Test.new.a # output: value2
    > >
    > > I don't understand (and I'm quite surprised), what is the difference in
    > > terms of OO design between class variables, the @@a in the example
    > > above, and class instance variables, the @a in the example?

    >
    > Currently class variables are also shared between different classes that
    > are part of the same inheritance tree. IMHO this is a rarely needed
    > feature and you're better off using regular instance variables on the
    > class (and referring to them via self.class.var from an instance).


    Where is this described? - It is dangerous if one doesn't know this.

    >>> Example >>>

    class Animal
    @@born = 0
    def initialize
    @@born += 1
    puts "a new animal"
    end
    def Animal.born
    @@born
    end
    end

    class Dog<Animal
    @@born = 0
    def initialize
    @@born += 1
    puts "a new dog"
    end
    def Dog.born
    @@born
    end
    end

    class Cat<Animal
    @@born = 0
    def initialize
    @@born += 1
    puts "a new cat"
    end
    def Cat.born
    @@born
    end
    end

    print "#{Cat.born} cats, #{Dog.born} dogs, #{Animal.born} animals\n"
    2.times{Dog.new}
    print "#{Cat.born} cats, #{Dog.born} dogs, #{Animal.born} animals\n"
    3.times{Cat.new}
    print "#{Cat.born} cats, #{Dog.born} dogs, #{Animal.born} animals\n"
    >>> Output >>>

    0 cats, 0 dogs, 0 animals
    a new dog
    a new dog
    2 cats, 2 dogs, 2 animals
    a new cat
    a new cat
    a new cat
    5 cats, 5 dogs, 5 animals
    >>> End of Example >>>
    Wolfgang Nádasi-Donner, Mar 13, 2005
    #9
  10. Lionel Thiry

    ts Guest

    >>>>> "W" == Wolfgang Nádasi-Donner <> writes:

    >>>> Output >>>

    W> 0 cats, 0 dogs, 0 animals
    W> a new dog
    W> a new dog
    W> 2 cats, 2 dogs, 2 animals
    W> a new cat
    W> a new cat
    W> a new cat
    W> 5 cats, 5 dogs, 5 animals
    >>>> End of Example >>>


    With this version of ruby

    uln% ruby -v
    ruby 1.9.0 (2005-03-14) [x86_64-linux]
    uln%

    The result is

    0 cats, 0 dogs, 0 animals
    a new dog
    a new dog
    0 cats, 2 dogs, 0 animals
    a new cat
    a new cat
    a new cat
    3 cats, 2 dogs, 0 animals


    --

    Guy Decoux
    ts, Mar 13, 2005
    #10
  11. ts wrote:

    > With this version of ruby
    >
    > uln% ruby -v
    > ruby 1.9.0 (2005-03-14) [x86_64-linux]
    > uln%
    >
    > The result is
    >
    > 0 cats, 0 dogs, 0 animals
    > a new dog
    > a new dog
    > 0 cats, 2 dogs, 0 animals
    > a new cat
    > a new cat
    > a new cat
    > 3 cats, 2 dogs, 0 animals


    So the behavior has been changed to lookup by surrounding module/class
    on method definition time?
    Florian Gross, Mar 13, 2005
    #11
  12. Lionel Thiry

    Lionel Thiry Guest

    Hello again!

    I've refactored a bit the code of Wolfgang. Now, it do a lot of reuse through
    inheretance. I'm really curious to know what this refactored code would give
    under ruby 1.9.0. Would you mind to test it for me, please?

    Here it is:

    class Animal
    @@born = 0
    def initialize
    @@born += 1
    self.class.anew
    end
    def self.anew
    puts "a new animal"
    end
    def self.born
    @@born
    end
    end

    class Dog<Animal
    def self.anew
    puts "a new dog"
    end
    end

    class Cat<Animal
    def self.anew
    puts "a new cat"
    end
    end

    print "#{Cat.born} cats, #{Dog.born} dogs, #{Animal.born} animals\n"
    2.times{Dog.new}
    print "#{Cat.born} cats, #{Dog.born} dogs, #{Animal.born} animals\n"
    3.times{Cat.new}
    print "#{Cat.born} cats, #{Dog.born} dogs, #{Animal.born} animals\n"

    It still gives the same output:
    0 cats, 0 dogs, 0 animals

    a new dog

    a new dog

    2 cats, 2 dogs, 2 animals

    a new cat

    a new cat

    a new cat

    5 cats, 5 dogs, 5 animals


    Thanks in advance,
    Lionel Thiry

    ts wrote:
    >>>>>>"W" == Wolfgang Nádasi-Donner <> writes:

    >
    >
    >>>>>Output >>>

    >
    > W> 0 cats, 0 dogs, 0 animals
    > W> a new dog
    > W> a new dog
    > W> 2 cats, 2 dogs, 2 animals
    > W> a new cat
    > W> a new cat
    > W> a new cat
    > W> 5 cats, 5 dogs, 5 animals
    >
    >>>>>End of Example >>>

    >
    >
    > With this version of ruby
    >
    > uln% ruby -v
    > ruby 1.9.0 (2005-03-14) [x86_64-linux]
    > uln%
    >
    > The result is
    >
    > 0 cats, 0 dogs, 0 animals
    > a new dog
    > a new dog
    > 0 cats, 2 dogs, 0 animals
    > a new cat
    > a new cat
    > a new cat
    > 3 cats, 2 dogs, 0 animals
    >
    >
    Lionel Thiry, Mar 14, 2005
    #12
  13. Lionel Thiry

    ts Guest

    >>>>> "L" == Lionel Thiry <> writes:

    L> It still gives the same output:
    L> 0 cats, 0 dogs, 0 animals
    L> a new dog
    L> a new dog
    L> 2 cats, 2 dogs, 2 animals
    L> a new cat
    L> a new cat
    L> a new cat
    L> 5 cats, 5 dogs, 5 animals

    with 1.9.0

    0 cats, 0 dogs, 0 animals
    a new dog
    a new dog
    2 cats, 2 dogs, 2 animals
    a new cat
    a new cat
    a new cat
    5 cats, 5 dogs, 5 animals


    --

    Guy Decoux
    ts, Mar 14, 2005
    #13
  14. Lionel Thiry

    Lionel Thiry Guest

    ts wrote:
    >>>>>>"L" == Lionel Thiry <> writes:

    >
    >
    > L> It still gives the same output:
    > L> 0 cats, 0 dogs, 0 animals
    > L> a new dog
    > L> a new dog
    > L> 2 cats, 2 dogs, 2 animals
    > L> a new cat
    > L> a new cat
    > L> a new cat
    > L> 5 cats, 5 dogs, 5 animals
    >
    > with 1.9.0
    >
    > 0 cats, 0 dogs, 0 animals
    > a new dog
    > a new dog
    > 2 cats, 2 dogs, 2 animals
    > a new cat
    > a new cat
    > a new cat
    > 5 cats, 5 dogs, 5 animals
    >
    >

    Thanks a lot! :)

    I expected it would give an error or the same output as the original code when
    executed in ruby 1.9.0.

    Would those modifications "correct" its behavior? (I hope I'm not too annoying
    asking to test code for me)

    class Dog<Animal
    @@born = 0
    def self.anew
    puts "a new dog"
    end
    end

    class Cat<Animal
    @@born = 0
    def self.anew
    puts "a new cat"
    end
    end

    Thanks in advance,
    Lionel Thiry
    Lionel Thiry, Mar 14, 2005
    #14
  15. Lionel Thiry

    ts Guest

    >>>>> "L" == Lionel Thiry <> writes:

    L> Would those modifications "correct" its behavior? (I hope I'm not too
    L> annoying asking to test code for me)

    no it does the same

    0 cats, 0 dogs, 0 animals
    a new dog
    a new dog
    2 cats, 2 dogs, 2 animals
    a new cat
    a new cat
    a new cat
    5 cats, 5 dogs, 5 animals

    you are still accessing the class variable in Animal


    --

    Guy Decoux
    ts, Mar 14, 2005
    #15
  16. --
    Wolfgang Nádasi-Donner

    "Lionel Thiry" <> schrieb im Newsbeitrag
    news:423473cb$0$28063$...
    > >>>>>>Example >>>>>

    > >
    > > class Mytest
    > > @@n_of_Mytest = 0
    > > def initialize
    > > @@n_of_Mytest += 1
    > > end
    > > def Mytest.n_of_Mytest
    > > @@n_of_Mytest
    > > end
    > > end
    > >
    > > puts Mytest.n_of_Mytest
    > > a = Mytest.new
    > > puts Mytest.n_of_Mytest
    > > b = Mytest.new
    > > c = Mytest.new
    > > puts Mytest.n_of_Mytest
    > > d = Mytest.new
    > > e = Mytest.new
    > > f = Mytest.new
    > > puts Mytest.n_of_Mytest
    > >
    > >>>>>>Output >>>>>

    > >
    > > 0
    > > 1
    > > 3
    > > 6
    > >
    > >>>>>>End of Example >>>>>

    > >
    > >
    > > O.K.?
    > >
    > >

    >
    > I've tested your code and I've been surprised that it actually worked. If

    I
    > correctly understand the mechanism, it's like the class object and its

    instances
    > are able to access class variables through '@@'. Undubitably, I know now

    why I
    > couldn't get along with that feature.
    >
    > Honestly, I largely prefer to think of classes as objects and use the

    class
    > instance variables when I want to share variables between instances. Using

    '@@'
    > doesn't seem reliable for me, as IMHO it violates some important OO

    principles,
    > the kind that if not followed leads to very embarrassing problems.
    >
    > Thanks for your help,
    > Lionel Thiry


    I think "@@" was based on Perl, where combinations of special characters
    have (very very) special meanings.

    The problem would be solved easily (I hope) with some kind of syntax like:

    class Mytest
    @@n_of_Mytest = 0
    def initialize
    Mytest.@@n_of_Mytest += 1
    end
    def Mytest.n_of_Mytest
    @@n_of_Mytest
    end
    end

    .... if the "@@"-notation will be stable (should be somehow, because all
    books for beginners will refer to).
    Wolfgang Nádasi-Donner, Mar 14, 2005
    #16
  17. Lionel Thiry

    Randy Kramer Guest

    (Sorry for the top posting.)

    I'd like to take a shot at answering Lionel's original question (what is the
    difference between class and instance variables). It seems convenient to use
    the result of Guy Decoux's example as an example.

    If you use class and instance variables "properly", you can achieve the
    following result, which can be very useful in some cases. Note that instance
    variables in the dog and cat class count the dogs and cats respectively,
    while the class variable (in the animal class) counts the animals (i.e., dogs
    + cats):

    0 cats, 0 dogs, 0 animals
    a new dog
    a new dog
    0 cats, 2 dogs, 2 animals
    a new cat
    a new cat
    a new cat
    3 cats, 2 dogs, 5 animals

    I am a newbie to Ruby, my answer is based on what I understand should happen
    with instance and class variables.

    regards,
    Randy Kramer

    On Tuesday 15 March 2005 08:58 am, ts wrote:
    > 0 cats, 0 dogs, 0 animals
    > a new dog
    > a new dog
    > 0 cats, 2 dogs, 0 animals
    > a new cat
    > a new cat
    > a new cat
    > 3 cats, 2 dogs, 0 animals
    Randy Kramer, Mar 15, 2005
    #17
  18. Lionel Thiry

    Randy Kramer Guest

    Oops, I need to correct myself:

    On Tuesday 15 March 2005 10:39 am, you wrote:
    > If you use class and instance variables "properly", you can achieve the
    > following result, which can be very useful in some cases. Note that
    > instance variables in the dog and cat class count the dogs and cats


    In the previous line, it would have been more clear (and correct ;-) to say
    "in the dog and cat *instances* (of the animal class)"


    > respectively, while the class variable (in the animal class) counts the
    > animals (i.e., dogs + cats):


    Randy Kramer
    Randy Kramer, Mar 15, 2005
    #18
  19. Lionel Thiry

    Lionel Thiry Guest

    Randy Kramer wrote:
    > (Sorry for the top posting.)
    >
    > I'd like to take a shot at answering Lionel's original question (what is the
    > difference between class and instance variables).

    Oops, there is some confusion here: "class variable", "class instance variable"
    and "instance variable" are three different things.

    @a in the context of instance code is an instance variable. "instance variable"
    is contained in an object, any object. As being internal to the object, it
    cannot be accessed from outside without a method call.

    Code example:
    class MyClass
    def initialize # instance method
    # instance code
    @a = "value"
    end
    def a
    @a
    end
    end
    puts MyClass.new.a # output: value

    @a in the context of class code is a "class instance variable". "class instance
    variable" is contained in an object, but not any one, it is contained in a
    class, as classes are objects too. Then, as being internal to the class object,
    it cannot be accessed from outside without a class method call.

    Code example:
    class MyClass
    #class code
    @a = "value"
    def self.a # class method
    # class code
    @a
    end
    def a # instance method
    # instance code
    @a
    end
    end
    puts MyClass.a # output: value
    puts MyClass.new.a # output: nil

    @@a whatever the context is a "class variable". "class variable" is "contained"
    in a class as if it was a "class instance variable" but without being one, it
    exists in "another world". In practical terms, the main difference is that '@@'
    is reachable from any instance without passing through any method call (which
    IMHO is poor OO design).

    Code example:
    class MyClass
    # class code
    @@a = 0
    def incr # instance method
    # instance code
    @@a += 1
    end
    def a # instance method
    # instance code
    @@a
    end
    def self.incr # class method
    # class code
    @@a += 1
    end
    def self.a # class method
    # class code
    @@a
    end
    end
    my_instance = MyClass.new
    other_instance = MyClass.new
    puts MyClass.a # output: 0
    puts my_instance.a # output: 0
    puts other_instance.a # output: 0
    my_instance.incr
    puts MyClass.a # output: 1
    puts my_instance.a # output: 1
    puts other_instance.a # output: 1
    other_instance.incr
    puts MyClass.a # output: 2
    puts my_instance.a # output: 2
    puts other_instance.a # output: 2
    MyClass.incr
    puts MyClass.a # output: 3
    puts my_instance.a # output: 3
    puts other_instance.a # output: 3

    Is it ok?

    Now, there is worse. @@a var is shared not only between the class and and its
    instances, but also with all inheriting classes and all their instances!

    Guy Decoux showed things are different in 1.9.0, but I don't understand how it
    works.

    --
    Lionel Thiry
    Lionel Thiry, Mar 15, 2005
    #19
  20. Lionel Thiry

    Randy Kramer Guest

    On Tuesday 15 March 2005 11:44 am, Lionel Thiry wrote:
    > Oops, there is some confusion here: "class variable", "class instance
    > variable" and "instance variable" are three different things.


    Ok, thanks! I think I've got the general idea--a class variable and class
    instance variable are almost the same, except the class variable is sort of a
    "renegade" global type of thing.

    Any more than that I'll probably have to let develop as this stuff soaks in a
    little more. ;-)

    Randy Kramer

    ---<good stuff snipped>---
    Randy Kramer, Mar 15, 2005
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    10
    Views:
    35,848
    jporter892
    Jun 6, 2011
  2. Gerry Sutton
    Replies:
    1
    Views:
    528
    Peter Otten
    Apr 16, 2005
  3. David Garamond
    Replies:
    5
    Views:
    227
    Ara.T.Howard
    Jun 8, 2004
  4. Replies:
    4
    Views:
    148
    Rick DeNatale
    Nov 17, 2007
  5. Sam Berry
    Replies:
    5
    Views:
    129
    Dave Angel
    Mar 29, 2013
Loading...

Share This Page