7

In ruby you can internally access variables directly via @var_name or via private getters attr_reader :var_name.

Which solution is more (semantically?) correct? Any advantages/disadvantages of using either solution 1 or solution 2?

Solution 1:

class Point
 def initialize(x, y)
   @x = x
   @y = y
 end

 def distance
   Math.sqrt(@x ** 2 + @y ** 2)
 end
end

Solution 2:

class Point
  def initialize(x, y)
   @x = x
   @y = y
  end

  def distance
    Math.sqrt(x ** 2 + y ** 2)
  end

private 
  attr_reader :x, :y

end
6
  • 1
    There are times when you want to use "Solution 3": Object#instance_variable_get. Suppose, for example, you wanted to compute the sum of squares of the values of all instance variables. You could write def sum_of_squares; instance_variables.reduce(0) { |t,v| t + instance_variable_get(v) ** 2 }; end, then Point.new(3,5).sum_of_squares #=> 34. Object#instance_variables returns an array of the instance variables. Commented Oct 31, 2015 at 19:25
  • @CarySwoveland That's tricky, I like it! I believe this approach is perfect for codegolf.stackexchange.com :D Commented Nov 1, 2015 at 9:48
  • attr_reader is just a shortcut to avoid writing the same, simple and generic getter methods for every attribute. It's part of DRY, imo. Commented Nov 1, 2015 at 15:33
  • @c650 it's not "just" a shortcut. It's C extension which is few times faster than writing methods by hand. omniref.com/ruby/2.2.0/files/… Commented Nov 1, 2015 at 15:49
  • @FilipBartuzi so I've heard. To me, however, if you're using Ruby there's a chance that you don't care about the few extra seconds. Wouldn't you use a different language if you actually cared about speed? Commented Nov 1, 2015 at 18:44

2 Answers 2

4

I would use the second option:

class Point
  def initialize(x, y)
   @x = x
   @y = y
  end

  def distance
    Math.sqrt(x ** 2 + y ** 2)
  end

private 

  attr_reader :x, :y    
end

For two reasons:

  1. attr_reader might be faster (as Filip Bartuzi already pointed out)
  2. Using attr_reader might make it easier to refactor that class later on by replacing the attr_reader with a custom getter method.
Sign up to request clarification or add additional context in comments.

1 Comment

Good solution. I can think of a third reason. Have a look at the comment I left on the question. Another way of doing that is def sum_of_squares; instance_variables.reduce(0) { |t,sym| t + send(sym.to_s[1..-1]) ** 2 }; end, then Point.new(3,5).sum_of_squares #=> 34. For each instance variable, this sends the string representation of its getter to the instance to obtain the value of the instance variable.
0

attr_reader :x, :y defines the following functions:

def x
  @x
end

def y
  @y
end

So both methods are equivalent and in fact identical. Performance is also similar in both cases, although attr_reader can be faster than some other variable accessing methods..

2 Comments

attr_reader is 3x faster than define_method: omniref.com/ruby/2.2.0/files/…
@FilipBartuzi the question is asking about direct access, though, which is not mentioned in the article.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.