1

I found weird behavior difference between an instance var (@var) and an attr_accessor. I believe when specified in attr_accessor, var=some_value should behave the same as @var=some_value. However, the below code snippet (LinkedList implementation in Ruby breaks when not using @ notation in line 10. Can anyone explain why this happens? I have tested in Ruby 2.6.1 and 2.6.5.

class LinkedList
  def initialize
    self.head = nil
    self.tail = nil
  end

  def add_first(data)
    if @head.nil?
      @head = Node.new(data) # Break if I use head without @
      @tail = @head 
    else
      @head = Node.new(data, @head)
    end
  end

  def add_last(data); 
    if @tail
      @tail.next_node = Node.new(data)
      @tail = @tail.next_node
    else
      add_first(data)
    end
  end

  def to_s
    result_str = ""
    curr_node = @head
    until (curr_node.next_node.nil?)
      result_str << curr_node.data << ", "
      curr_node = curr_node.next_node
    end
    # Last data is a special case without a comma
    result_str << curr_node.data
  end

  protected
  attr_accessor :head, :tail
end

class Node
  attr_accessor :data, :next_node
  def initialize(data=nil, next_node=nil)
    self.data = data
    self.next_node = next_node
  end

  def to_s
    data.to_s
  end
end

head = LinkedList.new
head.add_first("First")
head.add_first("Second")
head.add_first("Third")
head.add_last("Chicago")
head.add_last("Vegas")

puts head
trainsushi
  • 133
  • 1
  • 3
  • 2
    No, `var=` is not the same as `@var=`. You need to use `self.var=` with setters, otherwise Ruby will just define a local variable. – max pleaner Nov 09 '19 at 18:06
  • @maxpleaner But reading it as `another = var` seems working without `self.var`. Is that setter specific behavior? – trainsushi Nov 09 '19 at 18:10
  • This is not related to setters (which are just methods) but rather to assignment. See https://docs.ruby-lang.org/en/2.0.0/syntax/assignment_rdoc.html#label-Assignment+Methods – Christopher Oezbek Nov 09 '19 at 18:31
  • 2
    If a getter has been defined for `@var` there is no ambiguity when writing `x = var`: it's the same as `x = @var`. If you write `var = 3` Ruby creates a local variable `var` and assigns it a value `3`, regardless of whether you have an instance variable `@var` and a setter for it. If you write `self.var = 5` she sets `@var` equal to `5`. `self.` tells Ruby you are referring to the setter method. If `var = 5` caused `@var` to be set to `5` there would be no way to create a local variable `var`. Ruby wants you to be able to have both `@var` and `var`, even if it may not be good practice. – Cary Swoveland Nov 09 '19 at 18:48

0 Answers0