tags:

views:

78

answers:

3

In Ruby, isn't an instance variable like @foo and a class variable, @@bar?

In some code, I see a few

self.user_name = @name

or even

a += 1 if name != user_name   # this time, without the "self."
                              # and it is the first line of a method so 
                              # it doesn't look like it is a local variable

what is the self for? I thought it might be an accessor, but then can't it be just user_name instead of self.user_name? And I don't even see any code to make it an accessor, like attr_accessor, and not in the base class either.

A: 

Welcome in the "scope" hell!

Of course, if we have the full code, it should be easier to explain what you see.

Let me try:

class Woot
  attr_accessor :name

  def initialize
    self.name = 'Bistromathic Drive'
  end

  def foo
    puts name # hum… I don't know name. An attr? Oh Yes!
    name = '42' # New local var named 'name'
    puts name # Yeah! I know a local named 'name'
    puts self.name # I know the attr named 'name'
    name = 'Improbability Drive' # Change the local
    puts name 
    puts self.name # attr didn't move
    self.name = 'What was the question?'
    puts name
    puts self.name
  end
end
w = Woot.new
w.foo
# => Bistromathic Drive
42
Bistromathic Drive
Improbability Drive
Bistromathic Drive
Improbability Drive
What was the question?

The partial code you show is "suspect" to me, and I'd prefer to explain the base of var scope.

ook
+3  A: 

In Ruby:

  • @foo is an instance variable
  • @@bar is a class variable

Instance and class variables are private by default. It means, you can't set or get the value outside the class or the module itself.

If you want to set a value for foo, you need an attribute accessor.

class Model
  def foo
    @foo
  end

  def foo=(value)
    @foo = value
  end
end

For convenience (and performance reason), this is the same of

class Model
  attr_accessor :foo
end

Then you can do

m = Model.new
m.foo = "value"

And within the class you can doo

class Model

  # ...

  def something
    self.foo = "value"
    # equivalent to
    @foo = value
  end

end
Simone Carletti
+1  A: 

what is the self for? I thought it might be an accessor

It's a method at least - probably an accessor. self.name = something will call the method name= and self.name, or if no local variable called name exists, just name will call the method name.

but then can't it be just user_name instead of self.user_name?

When invoking the name= method you need the self because name = something would just create a local variable called name. When invoking the name method, it doesn't matter whether you write name or self.name unless there is also a local variable called name.

And I don't even see any code to make it an accessor, like attr_accessor, and not in the base class either.

If there is no call to attr_accessor and no explicit definition of name and name= anywhere, they might be handled by method_missing or defined by a different method than attr_accessor.

isn't self.user_name the same as @user_name

Only if it's defined to be. If you define user_name and user_name=? usingattr_accessorthey will get and set@user_name`. However if you define them through other means (or manually), they can do whatever you want.

For example ActiveRecord uses method_missing to "define" getter and setter methods that correspond to data base columns. So if your ActiveRecord class belongs to a table with a user_name column, you'll have user_name and user_name= methods without defining them anywhere. The values returned by user_name and set by user_name = will also not correspond to instance variables. I.e. there will be no instance variable named @user_name.

Another way to automatically define user_name and user_name= without using instance variables is Struct:

MyClass = Struct.new(:user_name)

Here MyClass will have the methods user_name and user_name=, but no instance variable @user_name will be set at any point.

sepp2k