Forum: Ruby Class variables or class singleton variables?

Posted by Damián M. González (igorjorobus)
on 2012-09-15 20:41
Guys, how are you?
 Watch this simple code first:


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

class << Foo
  attr_accessor :x
  @x = 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 = 0
  def initialize
    @@all_the_legs += 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 = 0
end

class Dog
  def initialize
    Dog.all_the_legs += 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 = 0 #with and without this line: same result for both
  def initialize
     @@all_the_legs += 4
  end
  def self.all_the_legs
     @@all_the_legs
  end
end

Dog.new; Dog.new; Dog.new; Dog.all_the_legs
#=> 12
Dogo.new; Dogo.new; Dogo.new; Dogo.all_the_legs
#=> 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.
Posted by Jan E. (jacques1)
on 2012-09-15 20:59
Hi,

You should definitely use class instance variables. The only situation 
where you might use a class variable is when you actually want the 
variable to be shared by the whole class family (i. e. all subclasses). 
Otherwise it makes no sense and can easily lead to problems (which you 
already discovered). Do *not* use it just to share the variable between 
the class and the instances. That's not what it's meant for. Many people 
even avoid class variables completely, because they're so hard to 
control.

By the way, your code does not do what you think it does. When you set a 
class instance variable in the singleton class, then this variable 
actually belongs to the singleton class and not the original class 
(which is the whole point of instance variables). So you have to set the 
variable in the Foo/Dog class:

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

or shorter

class Foo
  @x = 0
  singleton_class.send :attr_accessor, :x
end
Posted by Damián M. González (igorjorobus)
on 2012-09-15 21:26
Are we aren't talking about the same thing?

>class Foo
>  @x = 0
>  class << self
>    attr_accessor :x
>  end
>end

class << Foo
  attr_accessor :x
  @x = 1
end

 Are not the same? I mean(I may be wrong), when you define a class, self
is the class itself(Foo in this case), so it's not the same as class <<
Foo?
Posted by Damián M. González (igorjorobus)
on 2012-09-15 21:34
Yeee, I can see that they are not the same object, made this test:

irb(main):022:0> class << Foo
irb(main):023:1> self.object_id
irb(main):024:1> end
=> 10361628
irb(main):025:0> class Foo
irb(main):026:1> self.object_id
irb(main):027:1> end
=> 10361640

 But why?
Posted by Jan E. (jacques1)
on 2012-09-15 22:38
I don't get what you mean. The singleton class of a class is obviously 
not the same as the class itself, so getting different object IDs was to 
be expected.

Maybe you mean something different? If you wonder why I open the 
singleton class in the original class with "self" instead of outside the 
class with the name: That's both the same, but the first approach is 
less redundant and (in my opinion) more readable. But you should 
actually use "send".

And again: You cannot define a class instance variable for Foo in the 
singleton class of Foo. Those are two different variables:

class Foo
  @x = 'Foo'
  class << self    # or class << Foo
    @x = 'singleton'
  end
end

[Foo, Foo.singleton_class].each do |c|
  puts "#{c}: @x == #{c.instance_variable_get :@x}"
end

An instance variable always belongs to a specific object instance (hence 
the name). So if you define @x within the body of the singleton class, 
it will actually belong to the singleton class and not the original 
class.
Posted by 7stud -- (7stud)
on 2012-09-15 22:41
Damián M. González wrote in post #1076182:
> Yeee, I can see that they are not the same object, made this test:
>
> irb(main):022:0> class << Foo
> irb(main):023:1> self.object_id
> irb(main):024:1> end
> => 10361628
> irb(main):025:0> class Foo
> irb(main):026:1> self.object_id
> irb(main):027:1> end
> => 10361640
>
>  But why?
>

Because ruby has two distinct entities: a class and what's known as a
"singleton class".  When you write:

@some_var = 10

...that instance variable gets attached to whatever self is.  And inside
a singleton class, which is opened by writing:

class << Foo


end


self is the "singleton class".    Inside a regular class (but outside
any method definitions), self is the class.

A regular class inherits the methods from its singleton class.
Posted by Damián M. González (igorjorobus)
on 2012-09-15 22:56
Jan E. wrote in post #1076183:
> I don't get what you mean. The singleton class of a class is obviously
> not the same as the class itself, so getting different object IDs was to
> be expected.

 Yes. What I did was stupid, but I realized late to edit it.

> Maybe you mean something different? If you wonder why I open the
> singleton class in the original class with "self" instead of outside the
> class with the name: That's both the same, but the first approach is
> less redundant and (in my opinion) more readable. But you should
> actually use "send".

 Understood.

> And again: You cannot define a class instance variable for Foo in the
> singleton class of Foo. Those are two different variables:
>
> class Foo
>   @x = 'Foo'
>   class << self    # or class << Foo
>     @x = 'singleton'
>   end
> end
>
> [Foo, Foo.singleton_class].each do |c|
>   puts "#{c}: @x == #{c.instance_variable_get :@x}"
> end
>
> An instance variable always belongs to a specific object instance (hence
> the name). So if you define @x within the body of the singleton class,
> it will actually belong to the singleton class and not the original
> class.

 Now I know, the class itself is an object which can have instance
variables, and the singleton class of a class is kind of another object
that can have their own instance variables.

 class Foo  >> singleton class Foo
 ---------     -------------------
 @x = 1        @x = 3                #not the same variables

 Thanks for your help, I appreciate it.
Posted by Jan E. (jacques1)
on 2012-09-15 23:12
Damián M. González wrote in post #1076185:
>  Now I know, the class itself is an object which can have instance
> variables, and the singleton class of a class is kind of another object
> that can have their own instance variables.

Exactly. And the singleton class can also have its own methods and 
constants. In fact, the only relation to the original class is that the 
instance methods of the singleton class are the singleton methods of the 
original class (and vice versa). Apart from that it's a completely 
separate class.
Posted by Damián M. González (igorjorobus)
on 2012-09-15 23:30
Jan E. wrote in post #1076186:
> Exactly. And the singleton class can also have its own methods and
> constants. In fact, the only relation to the original class is that the
> instance methods of the singleton class are the singleton methods of the
> original class (and vice versa). Apart from that it's a completely
> separate class.

 Well this is amazing, I've tried to understand what you say, you mean
this?:

class Foo; end

class << Foo
  attr_accessor :x
  @x = 1
  def lalala
    "lalala #{@x}"
  end
end

class Foo
  @x = 2
  def self.lelele
    "lelele #{@x}"
  end
end

irb(main):018:0* Foo.lalala
=> "lalala 2"
irb(main):019:0> Foo.lelele
=> "lelele 2"
irb(main):020:0> Foo.singleton_class.instance_variable_get :@x
=> 1

 I'm referencing always to the Foo object when I call for lalala() and
lelele() and of course to the @x of the Foo object. Just when I',
referencing to the "ghost" Foo, I mean his singleton class I'll get the
value 1 which belong to the singleton class.
 And this should completely show what you mean:

irb(main):017:0> Foo.singleton_class.lalala
NoMethodError: undefined method `lalala' for #<Class:Foo>
        from (irb):17
        from C:/Ruby193/bin/irb:12:in `<main>'
irb(main):018:0> Foo.singleton_class.lelele
NoMethodError: undefined method `lelele' for #<Class:Foo>
        from (irb):18
        from C:/Ruby193/bin/irb:12:in `<main>'
irb(main):019:0> class << Foo
irb(main):020:1> def self.lololo
irb(main):021:2> @x
irb(main):022:2> end
irb(main):023:1> end
=> nil
irb(main):024:0> Foo.singleton_class.lololo
=> 1
Posted by Damián M. González (igorjorobus)
on 2012-09-15 23:56
To clear doubts, is this:

class Foo
  @x = 50
  def self.x
    @x
  end
end

 the same than this?:

Foo.class_eval do
  @x = 50
  def self.x
    @x
  end
end

 I think yes. And is the first snippet the same than this?:

class Foo; @x = 50; end
Foo.instance_eval do
  def x
    @x
  end
end

 and than this?:

class Foo; @x = 50; end
class << Foo
  def x
    @x
  end
end

 and than this?, what you mean in the beginning of this topic:

class Foo
  @x = 50
  class << self
    def x
      @x
    end
  end
end

 Of course is better use attr_accessor but is just for understanding
purpose. This is a good topic, newbies will find this usefull.
Posted by Jan E. (jacques1)
on 2012-09-16 00:13
Damián M. González wrote in post #1076189:
>  Of course is better use attr_accessor but is just for understanding
> purpose.

Yes, those code snippets all do the same (the second one requires the 
class to already exist, however).

So there are obviously many ways to do the same thing in Ruby. :-)
Posted by Josh Cheek (josh-cheek)
on 2012-09-16 04:15
(Received via mailing list)
On Sat, Sep 15, 2012 at 1:41 PM, Damin M. Gonzlez 
<lists@ruby-forum.com>wrote:

>     @@x = y
> above I should use, or is recommended to use, I really need your advice,
>   end
> end
>
>
> Dog.new; Dog.new; Dog.new; Dog.all_the_legs
> 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=0)
    @increment = increment
    @count     = count
  end

  def count!
    @count += @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 = Counter.new 4
  end
  reset!
end

Dog.leg_count # => 0
Dog.new
Dog.leg_count # => 4
Dog.new
Dog.leg_count # => 8
Dog.reset!
Dog.leg_count # => 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).
Posted by Damián M. González (igorjorobus)
on 2012-09-16 09:16
Josh Cheek wrote in post #1076199:

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

 Agree with you as with Jan.

> Singletons tend to force you into a workflow that you will later regret.

> 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).

 Nice to know it.

> 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).

 Do you mean that is good to track all the instances of a class in some
collection? Is not clear..
Posted by Josh Cheek (josh-cheek)
on 2012-09-16 11:45
(Received via mailing list)
On Sun, Sep 16, 2012 at 2:16 AM, Damin M. Gonzlez 
<lists@ruby-forum.com>wrote:

>  Do you mean that is good to track all the instances of a class in some
> collection? Is not clear..
>
>
No, I'm saying don't do this. You can count dog legs since that's a 
single
object, but don't implicitly try to track all of the dogs.
Posted by Damián M. González (igorjorobus)
on 2012-09-16 17:41
Josh Cheek wrote in post #1076220:

> No, I'm saying don't do this. You can count dog legs since that's a
> single
> object, but don't implicitly try to track all of the dogs.

 Well but I don't see another way of keep track of the objects which
I'll have to work around. I do this in many cases:

class Foo
  @instances = []        #can be a Hash too, whatever
  class << self
    attr_accessor :instances
  end
  attr_accessor :nickname
  initialize(nickname)
    @nickname = nickname
    Foo.instances = Foo.instances.push(self)
  end
end

 Do you say that I do not have to do this? How can I keep track of the
instances so, if I want to refer them in the future? 'cause later meaby
I'll need to do this:

Foo.instances.each do |x|
  puts x.nickname
end
Posted by Henry Maddocks (Guest)
on 2012-09-16 23:31
(Received via mailing list)
On 17/09/2012, at 3:41 AM, "Damin M. Gonzlez" <lists@ruby-forum.com> 
wrote:

>
> Do you say that I do not have to do this? How can I keep track of the
> instances so, if I want to refer them in the future? 'cause later meaby
> I'll need to do this:



foo_collection = []

foo_collection << Foo.new('nickname')

foo_collection.each do |x|
  puts x.nickname
end


Henry
Posted by Josh Cheek (josh-cheek)
on 2012-09-17 00:03
(Received via mailing list)
On Sun, Sep 16, 2012 at 10:41 AM, Damin M. Gonzlez
<lists@ruby-forum.com>wrote:

>   @instances = []        #can be a Hash too, whatever
>  Do you say that I do not have to do this? How can I keep track of the
> instances so, if I want to refer them in the future? 'cause later meaby
> I'll need to do this:
>
> Foo.instances.each do |x|
>   puts x.nickname
> end
>
>
Yeah, I would not do this. If you want to keep track of them, then
explicitly add them to a collection.

foo = Foo.new
foos << foo

Now, when foos gets garbage collected, your instances get garbage 
collected
(As opposed to the example above, where the class is always referenced 
by
the constant, and always references the collection containing the
instances, these instances are essentially permanent).


Furthermore, it allows the user to decide how to use the code. Do they 
want
to keep it in a collection? Then they can put it in a collection. Do 
they
want to just have one of these instances for a bit and then throw it 
away?
They can do that, too.

Lets say you want to do what Rails does with its rail ties, where they 
need
to hook into the system life cycle. Rails does it like this
https://github.com/rails/rails/blob/2801786e1a51b7...
is basically what it sounds like you're trying to do. This makes
decisions for users that Rails should not be making. The hoops I have 
had
to jump through to get away from this kind of invasive decision making
(even when it was my own dumb decisions in my own code) would widen your
eyes. If you want this kind of global registry of instances, let the
instantiator add the class to the registry.

Here is how I have handled this in my own code:

I have a gem that tests code samples embedded in files like READMEs. To
test the code sample, you need to know what strategy to use (i.e. run it
through rspec). The tests need to be able to specify what strategy they
should be run with, thus I maintain a list of strategies. But I do not
auto-add them, I allow whoever is creating the strategies to decide 
whether
they want it added to this list or not. Here is the code that maintains 
the
strategies:

https://github.com/JoshCheek/mountain_berry_fields...

Here is an example of an actual strategy, note that it explicitly 
registers
itself:

https://github.com/JoshCheek/mountain_berry_fields...
Posted by Damián M. González (igorjorobus)
on 2012-09-17 03:37
> Yeah, I would not do this. If you want to keep track of them, then
> explicitly add them to a collection.
>
> foo = Foo.new
> foos << foo
>
> Now, when foos gets garbage collected, your instances get garbage
> collected
> (As opposed to the example above, where the class is always referenced
> by
> the constant, and always references the collection containing the
> instances, these instances are essentially permanent).
>
>
> Furthermore, it allows the user to decide how to use the code. Do they
> want
> to keep it in a collection? Then they can put it in a collection. Do
> they
> want to just have one of these instances for a bit and then throw it
> away?
> They can do that, too.

 Woah, I had never thought this way...
 I see what you say kind of dangerous...meaby I have to take a closer
look.
 Also the software that I'm developing is not for programmers or
developers or enginners, just for final users. It will have a GUI, and
it will save big amounts of information trough time and that information
need to be showed to the users almost all the time, so in many ways
there's no option for save or not save some information, the software
just save it and need to keep it. This is a topic very interesting for
me, because I'm desingning the classes now, and soon will be programming
so I'm trying to discover which is the best strategy for keep track of
this objects, and wich is the easiest way to keep them alive once the
software is closed(once I know the first I'll know how to serialize it),
then I'll have to restore all the information back when the program
start again.

>foo_collection = []
>
>foo_collection << Foo.new('nickname')
>
>foo_collection.each do |x|
>  puts x.nickname
>end

 I see Henry Maddocks advice a little tangled. I can't visualize order
in my source code if I take the way he advice, meaby I'm wrong...don't
know.

 Thanks for be helping me.
Please log in before posting. Registration is free and takes only a minute.
Existing account (Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
No account? Register here.