开发者

What convention should I use for instance variables?

Is there any instance variable convention used in Rub开发者_如何学Goy code? Namely, I noticed that, in the examples section, instance variable are initialized using the '@' and then the code uses a variable name without the '@':

class BookInStock
  attr_reader: isbn
  attr_accessor: price

  def initialize (isbn, price)
    @isbn = isbn
    @price = Float (price)
  end

  def price_in_cents
    Integer (price * 100 + 0.5)
  end
end

And there are examples where the code, the instance variable is used all the time with the prefix '@'

class BookStock

  def set_price (price)
    @price = price
  end

  def get_price
    @price
  end
end

What is the difference these records? When should I use '@' only in the initialization of an object and when in all the class methods?


You can only use the instance variable name without @ if you have defined an attribute reader for this variable (with attr_reader or attr_accessor). This is a lightweight helper to create a method that returns the instance variable's value.

The difference is a question between using the public interface of your class or accessing private data. It is recommended to use the public interface in subclasses or included modules, for example. This ensures encapsulation. So you should not access instance variables from within subclasses or modules.

In the class itself, ask yourself this question: if the implementation of the attribute changes, should my usage the attribute change as well? If the answer is yes, use the instance variable directly; if it's no, use the public attribute.

An example. Suppose we have a Person class that represents a person and should contain that person's name. First there is this version, with only a simple name attribute:

class Person
  attr_reader :name

  def initialize(name)
    @name = name
  end

  def blank?
    !@name
  end

  def to_s
    name
  end
end

Note how we use the instance variable for the blank? method, but the public attribute for the to_s method. This is intentional!

Let's say that in a refactoring step we decide that the Person class should keep track of a first_name and last_name seperately.

class Person
  def initialize(first_name, last_name)
    @first_name, @last_name = first_name, last_name
  end

  def name
    "#{@first_name} #{@last_name}"
  end

  def blank?
    !@first_name and !@last_name
  end

  def to_s
    name
  end
end

We now change the name attribute to a regular method, which composes the name from a person's first and last name. We can now see that it is possible to keep the same implementation for to_s. However, blank? needs to be changed because it was dependent on the underlying data. This is the reason why to_s used the attribute, but blank? used the instance variable.

Of course, the distinction is not always easy to make. When in doubt, choose the public API over accessing private data.


In your first example, @price is an instance variable.

In the method definition for price_in_cents, price is actually a method call to price(). Because of Ruby's syntactic sugar, () is omitted.

It looks like there's no explicit definition for price(), but attr_accessor :price defined both price() and price=(value) a.k.a. getter and setter. You can try to comment out the attr_accessor :price line, you will get an "undefined local variable or method" exception when the BookInStock's instance calls price_in_cents.

An instance variable is always have an @ prefix. If no accessor methods defined, you can not use that name without @ prefix.


Using name = value is an error, because that creates a local variable named name. You must use self.name = value.

As for convention, you can only get away with using @name if you can guarantee that the accessors will always be lightweight attr_accessors. In all other cases, using @name over self.name will violate encapsulation and give yourself a headache. You gave the exact reason in your question — if there is extra logic in the getter/setter, you must duplicate it if you access the instance variable directly.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜