What is wrong with class variables? (newby)

Hello. I’m new to programming and new to ruby. I’ve recently
written a script and have asked people (including this group) about
components of the script. When people see that I’m using class
variables they ask me why and make a frowny face;).

So as I’m trying to get a better understanding of ruby I ask what’s
wrong with class variables? Or could it be how I’ve used them and not
a problem with class variables? I use class variables as a list where
I can add items for future reference. For example let’s say I have a
class variable (@@over_quota) that holds the list of users who are
over quoata. Then I iterate through the passwd file and check each
users home directory and if they are over quota I toss them onto the
class variable (@@over_quoata). Once I’ve iterated through the
passwd file I see if anything is in my class variable
(@@over_quota)and then iterate over the class variable sending email
to each user who’s over quoata.

I’ve recently (hour ago) learned about class instance variables and
I’m wondering if they are less frowned upon than class variables.
In the following example would it be better to use an class instance
variable over a class variable. From my perpective the end result
is the same.
#!/usr/bin/env ruby -w

class Simple
@@var = []
def Simple.append(l)
@@var << l
end
def Simple.return_var
@@var
end
end

one = Simple.append(“fred”)
puts Simple.return_var
two = Simple.append(“tony”)
puts Simple.return_var

./class_variable.rb
fred
fred
tony

#!/usr/bin/env ruby -w
class Simple
@var = []
def Simple.append(l)
@var << l
end
def Simple.return_var
@var
end
end

one = Simple.append(“fred”)
puts Simple.return_var
two = Simple.append(“tony”)
puts Simple.return_var

fred
fred
tony

Thanks in advance for your time!
Hopefully one day I’ll be able to answer someone elses question!
G.

On Nov 16, 2007, at 2:55 PM, [email protected] wrote:

So as I’m trying to get a better understanding of ruby I ask what’s
wrong with class variables?

There are probably profound philosophical reasons that they’re wrong,
but I think the most convincing reason is experience. They were
invented a long time ago (late 70’s, I believe), people used them,
and they turned out to cause problems. They made it harder to write a
program, leave it, come back to it, extend it, and have that work.
They made confusing bugs more likely. And (often) it’s just as easy
to do without them.

One lesson I’ve learned the hard way is that it’s almost always
better to use an instance than a class. For example, you have this:

one = Simple.append(“fred”)
puts Simple.return_var
two = Simple.append(“tony”)
puts Simple.return_var

I’d be tempted to do that if I knew – absolutely knew – that there
was never going to be more than one Simple. But I’ve learned to
prefer something like this:

simple = Simple.new
one = simple.append(“fred”)
puts simple.return_var
two = simple.append(“tony”)
puts simple.return_var

Why? Because almost every time I use the class instead of an
instance, I end up regretting it.

Notice that if you use the instance, you’ll change your
implementation of Simple to this:

class Simple
def initialize
@var = []
end

def append(i)
@var << i
end

def return_var
@var
end
end

Class variable is gone. And you can start taking advantage of other
Ruby features. For example, you can use attributes to avoid writing
some code:

class Simple
attr_reader :var # replaces the def of return_var

def initialize
@var = []
end

def append(i)
@var << i
end

end

In what I guess you’d call the modern style of coding, people write
tests before writing the code. What that does is make long-term
unpleasantness into immediate unpleasantness. For example, class
variables make classes hard to test, so testing encourages you not to
use them.

Now for the blatant plug: I describe this style of coding in
Everyday Scripting with Ruby http://www.pragprog.com/titles/bmsft.

and they turned out to cause problems. They made it harder to write a
program, leave it, come back to it, extend it, and have that work.
They made confusing bugs more likely. And (often) it’s just as easy

 Brian.

Now I understand the frowny faces. Your explanation is great in
that I don’t have to be a skilled programmer to comprehend your
point. Thank you very much for breaking it down like this.
I’ll see if my boss will get me the book;)
Thanks again. G.

On Nov 16, 2007 6:19 PM, Raul P. [email protected] wrote:

(cheap distribution of quasi-static info across a hierarchy), minimizing
purpose, and the intelligence of the programmer using them.
Great observations!

I’ve struggled with Ruby class variables myself. Of course I looked
at them in the light of my Smalltalk experience.

Smalltalk also has class variables which have the same kind of
visibility as in Ruby, class variables are visible to a sub-hierarchy
of Classes and their instances.

In Smalltalk they are (or at least used to be) used sparingly, and
almost always for static data. In effect they were used for the kind
of things you’d define as constants in a .h file.

The big difference that I can see between class variables in Ruby and
Smalltalk springs from the fact that while Smalltalk variable names
are declared, in Ruby they are introduced dynamically at first mention
during execution.

In Smalltalk the development environment would prevent redeclaration
of a class variable name, while in Ruby this can be done and causes
problems when a superclass creates a class variable which already
exists below, breaking the identity of the variable’s scope.

And, yes, I think that overuse of class variables for changeable state
is problematic either in Smalltalk or Ruby, but hadn’t thought about
that much until Raul so eloquently described it.


Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

[email protected] wrote:

When people see that I’m using class
variables they ask me why and make a frowny face;).

Brian M. wrote:

There are probably profound philosophical reasons that they’re wrong,
but I think the most convincing reason is experience. They were
invented a long time ago (late 70’s, I believe), people used them,
and they turned out to cause problems…

The trouble was (is?) that programmers used them to store ‘State’ that
was read and written by several components; the result was that the
complexity of the system (the number of possible ‘states’) grew
exponentially with each of those variables (of course, they are so easy
to use that they cut down the schedule at the beginning; these problems
are never only ‘technical’…).

Furthermore, in Ruby a ‘class variable’ is visible across the whole
hierarchy of subclasses (a modification done anywhere impacts all);
therefore, the potential for trouble is high.

Having said that, now for the part that may be controversial: I think
that class varibles can be VERY USEFUL, if used correctly; for example,
when there is a quasi-static condition to be transmitted to a hierarchy
of classes. Rails uses them profusely, for example in
action_controller/base.rb,


All requests are considered local by default, so everyone will

be exposed to detailed debugging screens on errors. When the

application is ready to go public, this should be set to false

@@consider_all_requests_local = true
cattr_accessor :consider_all_requests_local

There are many variables like that, which propagate quasi-static
conditions to the whole hierarchy. Notice also how they are complemented
with a ‘class attribute accessor’, so that they are accessed via methods
(which allows one day to change the implementation, if necessary).

Personally, I think that this is simply splendid: maximizing the benefit
(cheap distribution of quasi-static info across a hierarchy), minimizing
the evils.

Rails does even something more interesting: sometimes we want the
benefits of a class variable - eg, to inherit its content from the
superclass - but we want to be able to change it privately in a class;
this is done via the ‘class_inheritable_accessor’ (which plays a
fundamental role to chain modules to the View).

In conclusion, I think that very few things in programming are totally
‘evil’ (or totally ‘good’); it all depends from the context, the
purpose, and the intelligence of the programmer using them.