8

Possible Duplicate:
Why do Ruby setters need “self.” qualification within the class?

Can someone explain the difference between the following, and why it isn't as one might expect:

# version #1
class User
  def initialize(name, age)
    @name = name
    @age = age
  end
end

#version #2
class User
  attr_accessor :name, :age
  def initialize(name, age)
    @name = name
    @age = age
  end
end

#version #3
class User
  attr_accessor :name, :age
  def initialize(name, age)
    self.name = name
    self.age = age
  end
end

From what I understood, in methods, when you are assigning, you have to use the self keyword. Why can't you use this in an initialize method? Or can you? I tried using it and it didn't seem to work as expected, I'm just confused as to which technique to use and when and more importantly why.

I really hope someone can clear this up for me once and for all :)

Community
  • 1
  • 1
Blankman
  • 259,732
  • 324
  • 769
  • 1,199

2 Answers2

16

Version 1: The constructor creates two instance variables, @name and @age. These two variables are private (as are all Ruby instance variables), so you can't access them outside of the class.

Version 2: Exact same thing as #1 except that you're also defining a getter and setter method for the two variables. What attr_accessor does is create two methods for each parameter that allow you to get/set the value of the instance variable with the same name.

Version 3: Exact same as #2 except that in your constructor you're not setting the instance variables directly, instead you're calling the User#name= and User#age= methods to set the value of your instance variables instead of setting them directly.

To clarify the difference between setting the instance variable directly and calling a setter method, consider this example:

user = User.new "Rob", 26
user.name = "Joe"

Here you are not actually setting the @name variable of user directly, instead you are calling a method called name= on user which sets the value of @name for you. When you did the call to attr_accessor in versions #2 and #3, it defined that method for you. However in version #1 you did not call attr_accessor, so the example above would be invalid since there is no name= method.

robbrit
  • 17,560
  • 4
  • 48
  • 68
0

You don't need to use self in a method; for an instance variable, you should assign directly with @, like in version 1 or 2. self is not like in Python; it is used, for example, to declare a class method (like static function in C++).

Aleksander
  • 31
  • 3
  • Whether you should directly assign to instance variables is nebulous. I'm strongly on both sides of this one, don't think you can say that you should directly assign to it as there are a number of real benefits to using the setters. The only way I think you can make the argument that it is worth assigning to ivars directly is when you have no setters (use attr_reader instead of attr_accessor). – Joshua Cheek Sep 03 '12 at 01:08
  • Hm... I think assigning directly to ivars makes more sense in class methods, since ivars are supposed to be part of the implementation layer of classes, which is the one class methods use (in other words, I think ivars should be referred to in class methods for the same reason they shouldn't be outside of class methods - to separate the inner, "implementation", "private" layer of the class from the outer, "public" one). I recognise, however, that in any given context either one may make more sense semantically than the other. – Aleksander Sep 05 '12 at 12:48
  • In those kinds of situations, I sometimes put the `attr_accessor` after the `private` keyword. It's uglier, but then I get the benefits of using setters -- they're not as beneficial for classes as for instances, because classes aren't very likely to be inheriting the functionality, and also because mutable classes generally aren't a good idea since they're singletons) – Joshua Cheek Sep 05 '12 at 16:06