foo
foo

Reputation: 195

Aside from reading instance variable, what other purposes does attr_reader serve in ruby

I have the following code snippet:

class Modi
  include Comparable

  MEDAL_VALS = {"Gold" => 3, "Silver"=> 2, "Bronze" => 1}

  #commenting out attr_reader below breaks the code
  attr_reader :type

  def initialize(type)
    @type = type
  end

  def <=>(other)
    MEDAL_VALS[type] <=> MEDAL_VALS[other.type]
  end
end

My understanding is that attr_reader is a simply quick tool to print out instance variables for inspection/dev purposes.

When I comment out attr_reader :type and leaving def <=>(other) as it is, I get:

modi.rb:15:in `<=>': undefined local variable or method `type' for # 
<Modi:0x005609e878be80 @type="Bronze", @weight=5> (NameError)
Did you mean?  @type
    from modi.rb:29:in `<'
    from modi.rb:29:in `<main>'`

altering def <=>(other) to MODAL_VALS[@type] < MEDAL_VALS[other.type] (when attr_reader is commented out) leads to this error:

modi.rb:15:in `<=>': undefined method `type' for # 
<Modi:0x0055e62ce2feb0 @type="Silver", @weight=10> (NoMethodError)
    from modi.rb:29:in `<'
    from modi.rb:29:in `<main>'

Why is a getter, attr_reader :type, necessary in this case? (@type should work.. or even self.type - first time encountering this problem of calling an instance variable in another method of the same class)

Please explain.

Upvotes: 1

Views: 83

Answers (1)

Jay Dorsey
Jay Dorsey

Reputation: 3662

You can use attr_reader as a shortcut for creating a method that returns an instance variable name of the same name as the symbol.

You have at least 3 options:

  • Use attr_reader :type coupled with your @type = type assignment
  • Create your own def type; @type; end method
  • Modify your code to use @type and instance_variable_get:

if MEDAL_VALS[@type] < MEDAL_VALS[other.instance_variable_get('@type')]

attr_reader is not used (primarily) for debugging/inspection however. It's used to reduce boilerplate code.

Also, @type does work, for the current instance. You'll need to call @type with instance_variable_get per my last example to get the ivar from other.

Adding a public accessor method, either via attr_reader :type or a def type method adds clarity to the intent of the class (e.g. this ivar is meant to be accessed)

References:

Upvotes: 3

Related Questions