Class variables or class singleton variables?

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.

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

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?

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?

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.

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.

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.

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

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.

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.

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. :slight_smile:

On Sat, Sep 15, 2012 at 1:41 PM, Damin M. Gonzlez
[email protected]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).

Josh C. 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…

Josh C. 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

On Sun, Sep 16, 2012 at 2:16 AM, Damin M. Gonzlez
[email protected]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.

On 17/09/2012, at 3:41 AM, “Damin M. Gonzlez” [email protected]
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

On Sun, Sep 16, 2012 at 10:41 AM, Damin M. Gonzlez
[email protected]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/2801786e1a51b7cf7d7c3fd72b5fc9974f83f435/railties/lib/rails/railtie.rb#L125-134Which
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/blob/73e4c1e847c1029a384d84857db3a625d5cf74d4/lib/mountain_berry_fields/test.rb#L30-48

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

https://github.com/JoshCheek/mountain_berry_fields-magic_comments/blob/f9f38fb769eba058c14ffe0c0c14b46c2d891208/lib/mountain_berry_fields/test/magic_comments.rb#L14

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

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs