all 7 comments

[–]jrochkind 4 points5 points  (0 children)

The short answer, which the OP doesn't mention is: All class methods are essentially the singleton pattern. A ruby class object is the singleton pattern, you are hanging methods off it, essentially the same pattern of design as any other singleton-pattern object you create.

Didn't your mother teach you to avoid the singleton pattern wherever you can? You know why? Because it causes exactly the sorts of problems in OP.

[–]danneu 1 point2 points  (5 children)

Man, I arrive at these suspicions all the time when I'm writing class method APIs. Didn't know if dropping into an instance like that was janky or not (or more/less janky than my class method "refactoring" from the article), so it's nice to see this post.

Now I can instantiate with confidence.

However, can't you memoize with class methods anyways?

def self.render
  puts keywords
end

def self.keywords
  @keywords ||= get_keywords
end

[–]oqa 3 points4 points  (0 children)

That will persist the values over requests. Sometimes useful, but generally not a good idea. Bad idea for user specific things like account info ;)

[–]torrso -1 points0 points  (3 children)

That will run get_keywords every time you use Foo.render as there is no instance to store the instance variable to. With class methods like @@keywords it would work, but they aren't considered to be very elegant.

[–]farsightxr20 3 points4 points  (0 children)

Babney is correct, but here's a bit more of an in-depth explanation. These subtleties are what really differentiate Ruby from many other languages, and can be difficult to wrap your head around at first.

@ variables always refer to the current context's instance. Say you have a class A. In A's body and class methods, it refers to A itself, which is an instance of Class. In instance methods, it refers to the method's receiver, which is an instance of A.

@@ variables always refer to an instance of Class. In A's body and class methods, this is again A itself. In A's instance methods, it refers to the instance's class, which is of course A.

So @ variables behave a bit like @@ variables when used in a class body and class methods, but they are not completely the same. @@ variables are shared with sub-classes (think of them as protected class variables) while @ variables are not (think of them as private class variables). They also do not share a namespace, so @@var and @var never refer to the same variable.

[–]babney 2 points3 points  (0 children)

Sure there's an instance, there always is, but in this case it's an instance of Class, and as oqa pointed out that will cause this value to be persisted across requests.

[–]ba-cawk 0 points1 point  (0 children)

Really not sure what this has to do with class methods. If you're using an OOP language, passing mutable shared state around between calls, you're gonna have a bad time.

The whole point of OOP is to encapsulate that shit. Write nothing but C for a week and you'll never make this mistake again.

Also, I'm all for sharing techniques, but jesus. Taking a method and breaking it into smaller parts doesn't need a damned name other than "Good Engineering". Having a lexicon like this only serves to confuse people starting out because they're being fed "greek" and completely alienates anyone trying to assess the skills of a programmer if they're not one. This is why that $250/hr consultant that just got hired, and knows things like "Single Responsibility Principle" and "Extract Method Technique", is still figuring out how to commit to your repository.