When you are inside a class, you are not always forced to use the self receiver explicitly when calling a method residing in the same class (or higher in the hieararchy). However, there is a time when you HAVE to use self or else it just won’t do what you want : This time is when you call an attribute writer.
class Test
def assign_fiesta=(value)
@assigned_value=value
end
def not_an_assignment
@assigned_value
end
def some_method()
not_an_assignment # <== self is implicit
assign_fiesta = "Hello!" # <== self is not implicit! assign_fiesta is a local variable
self.assign_fiesta = "Hello!" # <== Now we're talking!
end
end
Why is this so? Well, it makes some sense when you think about it. If your attribute writers (methods trailing with an = sign) would'nt require to be called with an explicit receiver, how could you tell ruby when you want to assign to a local variable instead of calling a method? Sure, ruby could check if the thing to the left corresponded to the name of a method in the current class and, based on the answer, call a method or assign to a local variable. But what if the method did not reside in the current class but in the parent class... or in the parent class of the parent class (and so on)? It would become a great source of confusion, don't you think?
Say for example you had a method in your class that was setting the local variable color (color="blue"). This method could work without any problem for months... until you decide to add a new attribute writer with the name color= in the parent class. From now on (that is, if ruby would be using some detection technique like the one mentionned earlier), your initial method would not deal with the local variable color anymore, it would call the color= method in the parent class! This could get really messy and error prone.
So, instead of trying to guess if the thing to the left is a method with a trailing = sign or a local variable, ruby assumes that it is always a local variable and that the whole expression is a standard assignment. That being said, you could use self only to call attribute writers and omit it for other methods... but personally I don't like that kind of inconsistency.
I like to remind myself that a method never floats in the air and that it is always contained into an object. That's why most of the time I prefer to specify the receiver before the name of a method... no wonder if I'm outside or inside the object.
This is one of those simple things I didn’t know until I read Ruby for Rails. I highly recommend that book for illuminating numerous small details like this. Pickaxe is a great reference, but it glosses over a lot of those details in favor of a comprehensive picture of the language.
Another one of these little gotchas is that referencing a non-existent local variable or method raises an exception, whereas a non-existent instance variable returns nil.
We just got bitten by this.
Now I ask myself (and you): Isn’t there a way to make Ruby emit a warning when this kind of ambiguity occurs (When there is an attribute with that name?) Such a warning could help a lot.
Aljoscha,
This could be a nice to have but at the same time… it could become annoying to see warnings everytime you declare a local variable that happens to have the same name of some instance method in the class hierarchy. I think that Ruby should force us to use “self” even for attribute readers. That way people would stop getting caught by this terrible gotcha. Thanks for you comment!
Thanks for the explanation. I just decided to use self all the time, even when it’s not explicitly needed.
Thank you, that was enlightening. Wasted 1 hour of time wondering why my attributes aren’t getting set ;D
I for all time emailed this weblog post page to all my friends, since if like to read it next my friends will too.
I am really impressed with your writing skills as well as with
the layout on yourr weblog. Is this a paqid theme
or did you modiify it yourself? Either way keep up the
excellent quality writing, it’s rare tto see
a great blog like this one nowadays.
Very good post, from now on I’ll use self even on readers.