Class << self considered harmful... really?

On Thu, Nov 27, 2008 at 8:27 PM, Mark W. [email protected] wrote:

we need the construct later.
Great. That makes sense to me and I agree. Thanks for clarifying.
consistent convention and doesn’t delineate responsibility. That’s not a
given - it’s one of the things we’re discussing.
Ok, I think class << self is more consistent, because you can use the
same idioms as in class Foo. You cannot when using def
self.method_name.
I find that many of Ruby’s class stuff (@@ variables,
private_class_method, etc) as having to learn more stuff which I don’t
want to care about.

I’m wondering if this is a discussion about taste. I have my
experience with both approaches and you have yours. Just because
something works better for you does not mean its going to work better
for me and vice versa. I know that using class << self has been very
helpful in making my design better and it helps me to understand the
code vs the def self.method_name.
I see def self.method_name as a useful shortcut in irb or when there
are few (0 to many depending on the person and situation) simple
methods on the class. There is a point to where it, IMO, makes the
code more difficult to understand, though.

On Thu, Nov 27, 2008 at 5:57 PM, Brian T.
[email protected]wrote:

I’m wondering if this is a discussion about taste.

I think you’re right. I’ve been using the ‘def self.foo’ style in
various
languages for almost 20 years, so of course it feels more natural to me.
These languages (except for Smalltalk) had nowhere near the
metaprogramming
capability nor ‘objects all the way down’-ness of Ruby, and ‘class <<
self’
is one of those things.

///ark

On Thu, Nov 27, 2008 at 12:52 PM, Nathan Zook
[email protected] 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

class A
class C < B ; end

class B < A ; end


Zach D.
http://www.continuousthinking.com

On Thu, Nov 27, 2008 at 8:17 PM, Mark W. [email protected] wrote:

///ark

FWIW, the blog that led to this discussion suggested a performance
impact as well. As RSpec has gotten dinged for being slower than
alternatives, that interested me, so I did a little experiment def’ing
methods 10k times with def self.method and class << self; def method

def self.method ran an average of 10% faster.

Based on just that, I’ve all but eliminated class << self from rspec in
git.

Crazy?

On Thu, Nov 27, 2008 at 6:43 PM, Mark W. [email protected] wrote:

On Thu, Nov 27, 2008 at 1:59 PM, Brian T. [email protected]
wrote:

Its funny because I consider def self.foo harmful for a few reasons.

def self.method_name is often mixed with instance methods. This makes
reading the code confusing because there are two contexts that you
need to deal with.

Solution: Don’t do that.
When maintaining code, I often wish I could travel back in time and
tell the writer “Don’t do that”. :slight_smile:
course, and class methods are just instance methods of a different kind of
object. When you’re using them as such, opening up that object with class <<
self is a good idea. If you’re not, then you shouldn’t have very many of
them and wouldn’t need to refactor them out.
I consider classes & modules to be objects and therefore subject to
the rules of OOP. That one of the reasons why I love Ruby. The only
thing they have in common with global functions is that they are
easily accessible from anywhere in the process. Nonetheless, module
methods have encapsulated state.
Code evolves and things change. We usually don’t set out to overload
one object with too much responsibility. It happens with incremental
changes.
I find that using class << self makes it easy to identify, even when
I’m not looking for, the opportunity to extract an object. Usually
this has to do with the same state being passed in as an argument.

I also like how all of the class << self methods are organized into a
single section. Yes, its difficult to read if it takes more than a
screenful, but I prefer it to having to track down all of the def
self.method_name methods spread all over the place.

This is just a question of coding style. You can gather all your def
self.foos in one place, and you can have multiple class << self sections
(the latter being bad and the former good)
Thats true in theory, but in practice, I often see def
self.method_name spread all over the place and class << self in one
place. I’m not sure why, but I can guess that it has to do with not
thinking about object responsibility.

Also, class << self is more powerful. It allows you to use one way to
use your convenience methods (attr_*, include) and parser instructions
(public, private, protected). Nothing is worse than having to use both
def self.method_name and class << self.

I agree with that. But I also believe in doing the simplest thing that could
work, and using two extra lines of code when it’s not necessary fails that
test. If it is necessary, that’s a different matter, of course.
Yes we all like YAGNI, but its a trade-off. We all have seen YAGNI
bite us in the ass too, especially when it means turning off the
brain. I don’t think 2 extra filler lines of code make that strong of
an argument, when there is more than one class method (and even if
there is one class method IMO).
I think we also like how consistent conventions and delineation of
responsibility make code faster to read and understand.

When I get back into work on Tuesday, I’ll dig up what Matz says in RPL
(unless someone else has a copy?)
Sounds good.

Performance is one of those nasty things that can go from being a non-
issue to THE issue (next to correctness) in the blink of an eye. I am
curious, however. How much total performance difference did this
change make? I’m betting <1%.

Nathan

David C. wrote:

///ark

Crazy?

On Nov 28, 2008, at 11:52 AM, David C. wrote:

to me.
alternatives, that interested me, so I did a little experiment def’ing
methods 10k times with def self.method and class << self; def method

I’d be curious to see those benchmarks.

Also - re: performance: I’ve always wondered why RSpec (and other
ruby projects, for that matter) aren’t using Kernel#autoload instead
of Kernel#require. If we used autoload, we wouldn’t have to load
the code for, say, a matcher which is never used in a project.

Scott

On Fri, Nov 28, 2008 at 1:17 PM, Student [email protected]
wrote:

Performance is one of those nasty things that can go from being a non-
issue to THE issue (next to correctness) in the blink of an eye. I am
curious, however. How much total performance difference did this
change make? I’m betting <1%.
Yeah, this seems like premature optimization, if this were the only
reason. Rspec does not call class << foo nearly 10000 times.
Even if rspec did use class << foo 10000 times (each of which can
define multiple methods), it would make 0.x seconds of a difference in
the worst case (each class << object block only defines one method)
and 0.0x seconds difference in the best case (one object with 10000
methods defined in it).

Here are my numbers where method is defined on a single object 10000
times:
http://gist.github.com/raw/30285/a1731a82a0a59ec127b799ddb3b22763e9d06dd4

Heres another interesting benchmark where method is defined on 10000
objects 1 time:
http://gist.github.com/raw/30285/a99305dbeef2aed8453add68a5197cff3418bb69

On Fri, Nov 28, 2008 at 4:28 PM, Scott T.
[email protected] wrote:

I think you’re right. I’ve been using the ‘def self.foo’ style in various
impact as well. As RSpec has gotten dinged for being slower than
alternatives, that interested me, so I did a little experiment def’ing
methods 10k times with def self.method and class << self; def method

I’d be curious to see those benchmarks.
Here are some benchmarks I did.

On Sat, Nov 29, 2008 at 2:28 PM, Brian T. [email protected]
wrote:

I’m wondering if this is a discussion about taste.

FWIW, the blog that led to this discussion suggested a performance
impact as well. As RSpec has gotten dinged for being slower than
alternatives, that interested me, so I did a little experiment def’ing
methods 10k times with def self.method and class << self; def method

I’d be curious to see those benchmarks.
Here are some benchmarks I did.
Duh, I didn’t paste the link;
30285’s gists · GitHub

On Fri, Nov 28, 2008 at 10:28 PM, Scott T. <
[email protected]> wrote:

Also - re: performance: I’ve always wondered why RSpec (and other ruby
projects, for that matter) aren’t using Kernel#autoload instead of
Kernel#require. If we used autoload, we wouldn’t have to load the code
for, say, a matcher which is never used in a project.

I didn’t even know about that method. I don’t think I’ve ever seen it
used.
I’ll definitely try it out.

Cheers,
Aslak

On 28 Nov 2008, at 16:52, David C. wrote:

to me.
alternatives, that interested me, so I did a little experiment def’ing
methods 10k times with def self.method and class << self; def method

def self.method ran an average of 10% faster.

Based on just that, I’ve all but eliminated class << self from rspec
in git.

Crazy?

I think so.

I think Brian has argued eloquently that class << self leaves more
readable and maintainable code behind. I don’t know the RSpec code
very well, but I’d be surprised if the number of class methods used
would be significant enough that speeding them up will cause a
noticeable increase in the performance of RSpec overall, and it might
make the project harder to hack on, which would be a shame.

We have just under 4000 examples in the songkick code, taking about 7
minutes to run. If I get a chance I’ll try out both forks and see if I
can get you some stats.

Matt W.
[email protected]

On Nov 29, 2008, at 2:19 PM, Brian T. wrote:

Even if rspec did use class << foo 10000 times (each of which can
define multiple methods), it would make 0.x seconds of a difference in
the worst case (each class << object block only defines one method)
and 0.0x seconds difference in the best case (one object with 10000
methods defined in it).

Most certainly. Although there are certainly other performance
optimizations which would be easy to do, and it would be hard to
calculate how much time they actually cost. For instance, using
“return” actually performs a C longjmp (and the ruby interpreter does
nothing to remove return from the last statement in a method), so
it’s more efficient to avoid it - but how much could it really shave
off a user’s test suite time?

In this respect, RSpec can be seen more as library then an end-user
program, and it’s hard to anticipate exactly how the library is
going to be used. For instance, maybe mocks are barely used, but
certain matchers are used heavily. With a large enough test suite
and some good performance analysis these bottlenecks would become
clear, BUT the slowdown would be dependent on the nature of the
test suite.

Scott

On Sun, Nov 30, 2008 at 4:30 PM, Matt W. [email protected] wrote:

I think Brian has argued eloquently that class << self leaves more readable
and maintainable code behind.

I don’t think so. Nothing that has been said here has changed my
feeling that using class << self for class methods is an overly-clever
hack that makes it impossible to tell whether you’re looking at a
class or instance method in any class more than a page long. There’s
a reason Matz recommends against it, and a reason we recommend against
it in our codebase where I work. This isn’t just esthetics - I’ve
seen my own code comprehension speed noticeably diminished by files
where I had to keep scrolling up and down to keep track of what kind
of method I was looking at. If you keep all your classes to under a
page in length, good for you; but most Ruby programmers don’t have
that discipline in my experience. I don’t think it’s a practice worth
promulgating.


Avdi

Home: http://avdi.org
Developer Blog: Avdi Grimm, Code Cleric
Twitter: http://twitter.com/avdi
Journal: http://avdi.livejournal.com

On Sun, Nov 30, 2008 at 4:39 PM, Avdi G. [email protected] wrote:

I don’t think it’s a practice worth promulgating.

…not to mention that most noob Ruby programmers learned to use def
self.foo (or def ClassName.foo, if they are reading the 1st edition
pickaxe online), and coming across that class << self block is
confusing and gives them the (false) idea they have to understand
about singleton classes just to comprehend what’s going on in the
code. Keep it simple.


Avdi

Home: http://avdi.org
Developer Blog: Avdi Grimm, Code Cleric
Twitter: http://twitter.com/avdi
Journal: http://avdi.livejournal.com

On Wed, Nov 26, 2008 at 11:51 AM, Mark W. [email protected] wrote:

And class variables are problematic in Rails in development mode because of
class reloading.

Yes. They are.

Imgur

Peter

Here’s what The Ruby P.ming Language says about this:

“In general, it is clearer to define class methods as individual
singleton
methods without explicitly opening the eigenclass” (p. 258)

This is far from a blanket condemnation, and, as with the rest of the
book,
it’s not obvious whether it’s Matz or (non-Rubyist) Flanagan who’s
talking.

I don’t mean to “open” the discussion again. :slight_smile:

///ark

‘look at me, ma, I’m opening the eigenclass!’

“Honey, if you’re going to open your eigenclass, do it in your room.”

On 2 Dec 2008, at 22:31, Mark W. wrote:

Here’s what The Ruby P.ming Language says about this:

“In general, it is clearer to define class methods as individual
singleton methods without explicitly opening the eigenclass” (p. 258)

This is far from a blanket condemnation, and, as with the rest of
the book, it’s not obvious whether it’s Matz or (non-Rubyist)
Flanagan who’s talking.

I don’t mean to “open” the discussion again. :slight_smile:

Thanks for following up Mark.

I suggest that if there’s any life left in this thread, it staggers
over here for a few more rounds:
http://blog.mattwynne.net/2008/12/01/in-defence-of-class/

Matt W.
http://blog.mattwynne.net

On Thu, Dec 4, 2008 at 1:04 AM, Pat M. [email protected] wrote:

‘look at me, ma, I’m opening the eigenclass!’

“Honey, if you’re going to open your eigenclass, do it in your room.”

And if you keep doing it, you’ll go blind!


Rick DeNatale

Blog: http://talklikeaduck.denhaven2.com/
Twitter: http://twitter.com/RubyRedRick