Initializing Instance Variables: Self and Attributes
Recently, I learned that you can initialize an instance variable in two different ways. I already knew that instance variables were commonly initialized with an @ sign (as in, @instance_variable), but what’s new to me is that you can also do so with the prefix self. (as in, self.instance_variable).
For example, say I want to write a new class, one called Books that will store titles for each instance.
Of course, we start with a test:
In the past, I would have tried to make the test pass by writing something like this:
And that’s fine. The tests pass.
But what if I wanted to try out this new naming convention? Well, I would start by replacing the @ with self.:
But this on its own fails the tests:
So what’s going wrong? Is this whole alternative naming convention just a sham? Nope.
First of all - special thanks to Diana and my other fellow student apprentices for helping me figure this out.
It turns out that initializing instance variables with self. requires more than just an attr_reader. It also needs an attr_writer or, more elegantly, just an attr_accessor (which combines attr_reader and attr_writer).
Using attr_writer lets you set the value of an attribute (in this case, the instance variable ‘title’), and attr_reader lets you call the value of that attribute elsewhere.
To help flesh this out, say we wanted an option to add an author to our instances. We don’t want to require that new instances pass in an author argument when they’re initialized (since having an author is optional), so we create a separate method to set the value of author. Test first:
Put in the method to write our author attribute:
The tests pass. Now create tests for a method to read that attribute:
Make it pass:
Everything works.
But, as I’m sure you might have already guessed, there is a better way! What we’re doing here is writing and reading attributes for instances of our Books class. And, wouldn’t you know it, that’s exactly where attr_accessor is most helpful. We could replace the whole class we just completed like this:
All the tests still pass.
When you use the self. technique of initializing an instance variable with attr_accessor, you’re carrying out a very similar process. The key diffence is that attr_writer is using the argument you pass in when you initialize a new instance of the class.
[See my newer post about how to use the @instance_variable naming format with attr_reader to avoid the risks associated with typos, and also avoid unwanted code leaks]