From: Josh Cheek Date: 2012-09-16T11:13:42+09:00 Subject: Re: Class variables or Class singleton variables? --20cf307d024898c52204c9c8340c Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable On Sat, Sep 15, 2012 at 1:41 PM, Dami=E1n M. Gonz=E1lez wrote: > Guys, how are you? > Watch this simple code first: > > > class Foo > @@x =3D 1 > def self.x > @@x > end > def self.x=3D (y) > @@x =3D y > end > end > > class << Foo > attr_accessor :x > @x =3D 1 > end > > > I'm developing an aplication, and I'm wondering which way of the both > above I should use, or is recommended to use, I really need your advice, > 'cause I'm noob. This is the point: the instances of Foo class almost > will never access the class variable @@x. @@x is just a thing related > with the class itself, which is accessed generally from outside the > class, like...for example: > > > class Dog > @@all_the_legs =3D 0 > def initialize > @@all_the_legs +=3D 4 > end > end > > > And I just want to take a look sometimes at how many legs are...so: > > > class Dog > def self.all_the_legs > @@all_the_legs > end > end > > > This class variable will not be accessed anymore(after the initialize) > by any instance. So I'm wondering if is better to do this instead: > > > class << Dog > attr_accessor :all_the_legs > @all_the_legs =3D 0 > end > > class Dog > def initialize > Dog.all_the_legs +=3D 4 > end > end > > > Because I can see that if I choose the first way, and I want to Inherit > a class from Dog, I will fail: > > > class Dogo < Dog > @@all_the_legs =3D 0 #with and without this line: same result for both > def initialize > @@all_the_legs +=3D 4 > end > def self.all_the_legs > @@all_the_legs > end > end > > Dog.new; Dog.new; Dog.new; Dog.all_the_legs > #=3D> 12 > Dogo.new; Dogo.new; Dogo.new; Dogo.all_the_legs > #=3D> 24 > > > I have examples like this in my whole source code, so I'm thinking > which way to take. Hope you can view my point(the example could not be > the best): I need your advice about if is good to use class variables if > you almost don't use it for the access of instances, instead you need to > require that information from outside the class(suppose that I want to > maintain in a GUI the amount of legs that share all the dogs). It is > good in this cases to enter the singleton class of a class and define > accessors and instance variables to later be accessed? Thank you all. > > The instance variable solution is better, I advocate never using class variables for the reason that you showed. Singletons tend to force you into a workflow that you will later regret. So these days, I try fairly hard to avoid them. For your example, where it sounds like it is just a trick for debugging / getting information, and it has very little behaviour, I'd probably do what you're doing (I'm assuming we're deleting this code after we decide that it's doing what we think it is). If it were more complex than just incrementing a counter, or if you were planning on keeping it around for a while, I'd probably try to create some other object to handle the behaviour, then just store an instance of that object on this class. Maybe something like this: class Counter attr_reader :count def initialize(increment, count=3D0) @increment =3D increment @count =3D count end def count! @count +=3D @increment end end class Dog def self.leg_count @leg_counter.count end def self.new(*) @leg_counter.count! super end def self.reset! @leg_counter =3D Counter.new 4 end reset! end Dog.leg_count # =3D> 0 Dog.new Dog.leg_count # =3D> 4 Dog.new Dog.leg_count # =3D> 8 Dog.reset! Dog.leg_count # =3D> 0 In this example, it's of course overkill, but for something with more complex behaviour, try to get it where you can deal with it outside of the constraints of the singleton (e.g. to test it or to use it in a different way than imagined). Also, since I don't know what you're doing with it, let me warn against tracking all the instances in some collection. This will prevent them from being garbage collected, and will prevent you from being able to create instances where that is not the case (e.g. when you subclass pretty much anything in Rails, it tracks that and then does things with it that you may reasonably want it to not do). --20cf307d024898c52204c9c8340c Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable On Sat, Sep 15, 2012 at 1:41 PM, Dami=E1n M. Gonz=E1lez &= lt;lists@ruby-for= um.com> wrote:
Guys, how are you?
=A0Watch this simple code first:


class Foo
=A0 @@x =3D 1
=A0 def self.x
=A0 =A0 @@x
=A0 end
=A0 def self.x=3D (y)
=A0 =A0 @@x =3D y
=A0 end
end

class << Foo
=A0 attr_accessor :x
=A0 @x =3D 1
end


=A0I'm developing an aplication, and I'm wondering which way of the= both
above I should use, or is recommended to use, I really need your advice, 'cause I'm noob. This is the point: the instances of Foo class almo= st
will never access the class variable @@x. @@x is just a thing related
with the class itself, which is accessed generally from outside the
class, like...for example:


class Dog
=A0 @@all_the_legs =3D 0
=A0 def initialize
=A0 =A0 @@all_the_legs +=3D 4
=A0 end
end


=A0And I just want to take a look sometimes at how many legs are...so:


class Dog
=A0 def self.all_the_legs
=A0 =A0 =A0@@all_the_legs
=A0 end
end


=A0This class variable will not be accessed anymore(after the initialize) by any instance. So I'm wondering if is better to do this instead:


class << Dog
=A0 attr_accessor :all_the_legs
=A0 @all_the_legs =3D 0
end

class Dog
=A0 def initialize
=A0 =A0 Dog.all_the_legs +=3D 4
=A0 end
end


=A0Because I can see that if I choose the first way, and I want to Inherit<= br> a class from Dog, I will fail:


class Dogo < Dog
=A0 @@all_the_legs =3D 0 #with and without this line: same result for both<= br> =A0 def initialize
=A0 =A0 =A0@@all_the_legs +=3D 4
=A0 end
=A0 def self.all_the_legs
=A0 =A0 =A0@@all_the_legs
=A0 end
end

Dog.new; Dog.new; Dog.new; Dog.all_the_legs
#=3D> 12
Dogo.new; Dogo.new; Dogo.new; Dogo.all_the_legs
#=3D> 24


=A0 I have examples like this in my whole source code, so I'm thinking<= br> which way to take. Hope you can view my point(the example could not be
the best): I need your advice about if is good to use class variables if you almost don't use it for the access of instances, instead you need t= o
require that information from outside the class(suppose that I want to
maintain in a GUI the amount of legs that share all the dogs). It is
good in this cases to enter the singleton class of a class and define
accessors and instance variables to later be accessed? Thank you all.

=A0
The instance variable solution is better, I advocate = never using class variables for the reason that you showed.

Singleto= ns tend to force you into a workflow that you will later regret. So these d= ays, I try fairly hard to avoid them. For your example, where it sounds lik= e it is just a trick for debugging / getting information, and it has very l= ittle behaviour, I'd probably do what you're doing (I'm assumin= g we're deleting this code after we decide that it's doing what we = think it is).

If it were more complex than just incrementing a counter, or if you wer= e planning on keeping it around for a while, I'd probably try to create= some other object to handle the behaviour, then just store an instance of = that object on this class. Maybe something like this:

class Counter
=A0 attr_reader :count
=A0
=A0 def initialize(i= ncrement, count=3D0)
=A0=A0=A0 @increment =3D increment
=A0=A0=A0 @co= unt=A0=A0=A0=A0 =3D count
=A0 end
=A0
=A0 def count!
=A0=A0=A0= @count +=3D @increment
=A0 end
end

class Dog
=A0 def self.leg_count
=A0=A0=A0 @leg_counter.count
= =A0 end
=A0
=A0 def self.new(*)
=A0=A0=A0 @leg_counter.count!
= =A0=A0=A0 super
=A0 end
=A0
=A0 def self.reset!
=A0=A0=A0 @leg= _counter =3D Counter.new 4
=A0 end
=A0 reset!
end

Dog.leg_count # =3D> 0
Dog.new
Dog.leg_co= unt # =3D> 4
Dog.new
Dog.leg_count # =3D> 8
Dog.reset!
Do= g.leg_count # =3D> 0


In this example, it's of course over= kill, but for something with more complex behaviour, try to get it where yo= u can deal with it outside of the constraints of the singleton (e.g. to tes= t it or to use it in a different way than imagined).

Also, since I don't know what you're doing with it, let me warn= against tracking all the instances in some collection. This will prevent t= hem from being garbage collected, and will prevent you from being able to c= reate instances where that is not the case (e.g. when you subclass pretty m= uch anything in Rails, it tracks that and then does things with it that you= may reasonably want it to not do).

--20cf307d024898c52204c9c8340c--