As a beginner, I've not quite got my head around self
so I'm having trouble understanding how the self.blogs
in initialize, and blogs
then self.blogs
on the next line after in the add_blog
method, are all working together in the below code.
Why does blogs
in the add_blog
method access the same variable as self.blogs
in initalize?
And then why is self.blogs
used afterwards to sort the blogs
array?
Also, would it matter if I used @blogs
in initialize, instead of self.blogs
?
class User
attr_accessor :username, :blogs
def initialize(username)
self.username = username
self.blogs = []
end
def add_blog(date, text)
added_blog = Blog.new(date, self, text)
blogs << added_blog
self.blogs = blogs.sort_by { |blog| blog.date }.reverse
added_blog
end
end
For most method calls on self, self.method_name
is equivalent to just method_name
. That's not the case for methods whose name ends with an =
, though.
The first thing to note, then, is that self.blogs = etc
doesn't call a method named blogs
and then somehow 'assign etc to it'; that line calls the method blogs=
, and passes etc
to it as an argument.
The reason you can't shorten that to just blogs = etc
, like you can with other method calls, is because blogs = etc
is indistinguishable from creating a new local variable named blogs
.
When, on the previous line, you see a bare blogs
, that is also a method call, and could just as easily have been written self.blogs
. Writing it with an implicit receiver is just shorter. Of course, blogs
is also potentially ambiguous as the use of a local variable, but in this case the parser can tell it's not, since there's no local variable named blogs
assigned previously in the method (and if there had been, a bare blogs
would have the value of that local variable, and self.blogs
would be necessary if you had meant the method call).
As for using @blogs =
instead of self.blogs =
, in this case it would have the same effect, but there is a subtle difference: if you later redefine the blogs=
method to have additional effects (say, writing a message to a log), the call to self.blogs =
will pick up those changes, whereas the bare direct access will not. In the extreme case, if you redefine blogs=
to store the value in a database rather than an instance variable, @blogs =
won't even be similar anymore (though obviously that sort of major change in infrastructure will probably have knock-on effects internal to the class regardless).