3 ms·
I'm about 5-6 years into my Ruby programming career (and 5-6 years into my OO programming career) and this is something that I've been wondering about lately.
by omgsean 14y ago
I'm about 5-6 years into my Ruby programming career (and 5-6 years into my OO programming career) and this is something that I've been wondering about lately. When I read Design Patterns for Ruby Russ Olsen seemed to generally write classes that require instantiation, but when I look at the work of other Rubyists that I admire they're often writing classes that are nothing but class methods.
I'm starting to get a pretty good feel for it, but what are the criteria that you use to determine if a class should be stateless or not?
- ori_b 14y agoThe rule of thumb I use in most cases: Can it be written statelessly without contortions or large inefficiencies? If so, then I make it stateless. Depending what is idiomatic in the language and project, I will usually put it into a function instead of a class. I find stateless code easier to reason about.
- aphyr 14y agoClasses exist to bundle state; if there's no need for state, there often shouldn't be a class in the first place. I tend to use module_fun for that, or just: module Foo def self.some_stateless_method ... end end Foo.some_stateless_method class MyController include Foo def index some_stateless_method end end and so forth. People think of modules as being mixins, but they're actually just function namespaces--which you can happen to bind into class contexts via include/extend. I tend to use class methods where: a.) The class exists, because you want state, and b.) The function operates principally on, or is only useful in, the context of that class, but c.) The function isn't bound to the object's state. That last requirement is fuzzy, since the call semantics are different: self.class.foo is awkward, so I'll often write instance methods which don't actually depend on the state, just taking advantage of the local namespace.
- tenderlove 14y agoI think it depends on the situation, and it's difficult to for me to describe. I try to think about it like this: I am writing a class to represent a car. I need to know if the cars doors are opened or closed. The `open` or `closed` attribute is the state of the car, so it makes sense that the Car object would have that state. Now compare that to the use of `LanguageDetector` from the example: LanguageDetector.new(@comment).set_language Presumably this object is keeping a reference to the comment for it's internal state. When I'm dealing with an object, I like to say in my head "language detector, can you tell me the language for some text?". Nothing in my question gave the text a 1:1 relationship with the language detector. Since my question did not identify a relationship, I would not make the comment a part of the LanguageDetector object. I'd rather write something like this: detector = LanguageDetector.new language = detector.detect_language(@comment) @comment.language = language What might the LanguageDetector actually want to have as it's state? I think maybe things like encodings, or particular languages it supports. The question I ask is "language detector, what encodings or languages do you support?", and the relationship becomes clear. For example: detector = LanguageDetector.new(:encodings => [...], :languages => [...]) # etc I hope that makes sense, and that I don't sound too crazy (talking to myself and whatnot).