[rspec-users] class << self considered harmful... really?

Zach Dennis zach.dennis at gmail.com
Thu Nov 27 13:09:53 EST 2008


On Thu, Nov 27, 2008 at 12:52 PM, Nathan Zook <Nathan at pierian-spring.net> wrote:
> That's not a surprise, that's a feature. Know the difference between class
> variables and class instance variables.

Said the preacher to the choir.

But even features can cause surprises. It's a surprise when you're the
consumer of someone else's code. For example, this problem used to
exist in Rails:

   ActionMailer::Base.smtp_settings = { some_config_settings }

Then to give a particular mailer subclass different smtp settings,
this seemed like a logical thing to do:

   class MyMailer  < ActionMailer::Base ; end
   MyMailer.smtp_settings = { my_other_config }

I was a bit surprised when it overrode the smtp settings for every
single mailer, when I expected the change to just go to MyMailer's
smtp_settings. This and many others like it have since been fixed in
Rails, but Rails is not the only code I've seen do this.

Realistically it may take people using class variables incorrectly to
see they really wanted a class instance variable. Hopefully these
discussions help inform people before they have to make that mistake
in code they are writing,

Zach


>
> Zach Dennis wrote:
> ...
>>
>> AFAIK it isn't any safer from a threading point of view.
>>
>> My biggest hate of class variables is that they are shared throughout
>> an entire inheritance hierarchy (and I do not find @@ aesthetically
>> pleasing). Class instance variables are not.
>>
>> class A
>>   def self.foo
>>      @@foo
>>   end
>>
>>   def self.foo=a
>>       @@foo = a
>>   end
>> end
>>
>> class B < A ; end
>> class C < B ; end
>>
>> A.foo = 1
>> A.foo # => 1
>>
>> C.foo # => 1
>> C.foo = 10
>> C.foo # => 10
>> A.foo # => 10 -- surprise!
>>
>> Class instance variables don't have this problem.
>>
>> class A
>>   def self.foo
>>      @foo
>>   end
>>
>>   def self.foo=a
>>       @foo = a
>>   end
>> end
>>
>> class B < A ; end
>> class C < B ; end
>>
>> A.foo = 1
>> A.foo # => 1
>>
>> C.foo # => nil
>> C.foo = 10
>> C.foo # => 10
>> A.foo # => 1
>>
>>
>>
>



-- 
Zach Dennis
http://www.continuousthinking.com
http://www.mutuallyhuman.com


More information about the rspec-users mailing list