user1706938
user1706938

Reputation: 131

ruby style and instance variables

Something that I see in a lot of code:

class Foo
  attr_accessor :bar

  # lots of code omitted

  def baz
    'qux' if bar
  end
end

The exact form of the baz method is not too important - it's just that bar here is a reference to the getter method for the instance variable @bar, called from within the instance's class. I would favor retrieving the value from @bar explicitly. Are there any opinions on this? I've never seen anything in the ruby style guide or similar covering this. I personally find that doing the former makes it harder to read and understand, especially when classes are over several hundred lines long.

Edit:

Perhaps to illustrate what I would consider to be the awkwardness of this design, let's re-evaluate a pretty standard initialize method:

class Foo
  attr_accessor :bar, :qux

  def initialize(bar, qux)
    @bar = bar
    @qux = qux
  end
end

If we use the setter method, we cannot use bar = ? by analogy. Instead, we have:

class Foo
  attr_accessor :bar, :qux

  def initialize(bar, qux)
    self.bar = bar
    self.qux = qux
  end
end

which has lost some of the elegance of the first. We have a more flexible design in that we are now free to rewrite our setter method and do away with attr_writer. But I've just some points in style, and it feels a lot like configuration over convention rather than the converse, something that Russ Olsen has declared a design 'pattern' not just of Rails but of Ruby too.

Upvotes: 1

Views: 815

Answers (3)

Peter Alfvin
Peter Alfvin

Reputation: 29419

Accessing the attribute through the getter has the advantage of providing encapsulation. The use of an instance variable to store the value is an implementation detail in some respects. Whether that's appropriate is, of course, situational. I don't recall reading anything explicit this style issue, however.

Found https://softwareengineering.stackexchange.com/questions/181567/should-the-methods-of-a-class-call-its-own-getters-and-setters, which discusses the issue from a language-independent point of view. Also found https://www.ruby-forum.com/topic/141107, which is ruby-specific, although it doesn't break any new ground, let alone imply a Ruby standard.

Update: Just came across the following statement on page 24 of http://www.amazon.com/Practical-Object-Oriented-Design-Ruby-Addison-Wesley/dp/0321721330/ref=sr_1_1?s=books&ie=UTF8&qid=1376760915&sr=1-1, a well-respected book on Ruby: "Hide the variables, even from the class that defines them, by wrapping them in methods." (emphasis added). It goes on to give examples of methods in the class using the accessor methods for access.

Upvotes: 5

7stud
7stud

Reputation: 48599

I would favor retrieving the value from @bar explicitly. Are there any opinions on this?

Yes, direct access is not as flexible of a design. Getters and setters can be used to transform values. That is why java programmers spend half their lives banging out do nothing setters and getters for their private variables--they want to present the setters and getters as their api, which allows them to change their code in the future to transform values on the way in or the way out without changing the api.

Then ruby came along with the neat attr_accessor method, which meant that writing do nothing setters and getters wasn't painful anymore.

Python goes one step further. In python, instance variables are public and you can directly access them, e.g.

print my_dog.age 

A java programmer writing a python program would implement get_age() and set_age() methods:

class Dog:
    def get_age(self):
        return self.age

    def set_age(self, age):
        self.age = age

The java programmer would then fly over all the towns in the land and drop leaflets describing the getter and setter methods as the api for getting and setting the age instance variable, and they would warn people not to access the instance variables directly--or else things might break.

However, python has a feature that allows programmers to eliminate getters and setters until they are actually needed to do something useful--rather than dumbly getting or setting a value. Python allows you to transform direct access to instance variables by client code into method calls. To the client it's transparent. For instance, the client code may be accessing an instance variable in a class by writing:

my_dog.age  

Python allows the writer of the class to subsequently implement a method named age(), and my_dog.age can be made to call that method instead of directly accessing the instance variable (note that in python, unlike in ruby, you can't normally call a method without the parentheses). The newly implemented age() method can then do anything it wants to the age instance variable before returning it to the client code, e.g. transform it into human years, or retrieve the age from a database.

Upvotes: 2

Translunar
Translunar

Reputation: 3816

It's actually faster to use a getter, mainly because attr_reader and attr_accessor are written in C instead of Ruby.

As someone who's been coding Ruby for a few years, I think using attr_* is much more readable. But that's probably just something I've gotten used to.

Upvotes: 1

Related Questions