Attr_reader

On p. 30-31 of “Programming Ruby (2nd ed)”, there is this example:

class Song
attr_reader :name, :artist, :duration
end

and the text says:

“The corresponding instance variables, @name, @artist, and @duration,
will be created for you.”

But I discovered that I still have to define an initialize method to
create objects:

class Song
attr_reader :x, :y, :z

def initialize(x, y, z)
    @x = x
    @y = y
    @z = z
end

end

s = Song.new(10, 20, 30)
puts s.x

So, it seems like initialize is what creates the instance variables.
Or, does attr_reader somehow do its thing before initialize is called?
If so, why is it considered important to know that attr_reader creates
the instance variables instead of initialize?

From: 7stud 7stud [mailto:[email protected]]

"The corresponding instance variables, @name, @artist, and @duration,

will be created for you."

that should read: “The corresponding instance variable getter and setter
methods will be created for you.”

irb(main):092:0> system “qri instance_variables”
---------------------------------------------- Object#instance_variables
obj.instance_variables => array

 Returns an array of instance variable names for the receiver. Note
 that simply defining an accessor does not create the corresponding
 instance variable.

    class Fred
      attr_accessor :a1
      def initialize
        @iv = 3
      end
    end
    Fred.new.instance_variables   #=> ["@iv"]

#So, it seems like initialize is what creates the instance variables.

not really.

irb(main):097:0> class Song2
irb(main):098:1> attr_accessor :x, :y
irb(main):099:1> end
=> nil

note, no initialization there

irb(main):106:0> ix=Song2.new
=> #Song2:0xb7d7efa8
irb(main):107:0> ix.instance_variables
=> []
irb(main):108:0> ix.x=“hi, i am x”
=> “hi, i am x”

note the assignment using the setter method automatically created using
attr_accessor

irb(main):109:0> ix.x
=> “hi, i am x”

now, we’ve created an instance var

irb(main):110:0> ix.instance_variables
=> [“@x”]
irb(main):111:0>

kind regards -botp

Peña, Botp wrote:

From: 7stud 7stud [mailto:[email protected]]

"The corresponding instance variables, @name, @artist, and @duration,

will be created for you."

that should read: “The corresponding instance variable getter and setter
methods will be created for you.”

Huh? As far as I can tell, no setter methods are created:

class Song
attr_reader :x, :y, :z

def initialize(x, y, z)
    @x = x
    @y = y
    @z = z
end

end

s = Song.new (10, 20, 30)
puts s.x
s.x = 40

–output:–
10
r1test.rb:22: undefined method `x=’ for #<Song:0x253c8 @y=20, @x=10,
@z=30> (NoMethodError)

#So, it seems like initialize is what creates the instance variables.

not really.

irb(main):097:0> class Song2
irb(main):098:1> attr_accessor :x, :y
irb(main):099:1> end
=> nil

note, no initialization there

My program has no attr_accessor line (the book hasn’t mentioned
attr_accessor yet). Your saying the initialize method in my program
doesn’t create the instance variables? What does?

Ok. Thanks.

From: 7stud *** [mailto:[email protected]]

Huh? As far as I can tell, no setter methods are created:

class Song

attr_reader :x, :y, :z

sorry, i misread your post. attr_reader only gives getters.

My program has no attr_accessor line (the book hasn’t mentioned

attr_accessor yet). Your saying the initialize method in my program

doesn’t create the instance variables?

my english is poor. sorry. initialize will create it, but it’s not the
only way. you can create your own setters.

kind regards -botp

You do have to make your own
class Song
def initialize(x, y, z)
@x = x
@y = y
@z = z
end
end
song=Song.new(x,y,z)

then
attr_reader will make the methods
song.x, song.y, and song.z

attr_accessor will make the methods
song.x, song.x=, song.y, song.y=, song.z, and song.z=

attr_writer I know exists, but have never actually used.

attr(:method,false) == attr(:method) == attr_reader(:method)
attr(:method,true) == attr_accessor(:method)

Actually, I think attr_reader does create the instance variables:

class Song
attr_reader :name, :artist, :duration
end

song = Song.new

puts song.name
puts song.artist
puts song.duration

puts song.fake

–output:—
nil
nil
nil
r1test.rb:18: undefined method `fake’ for #Song:0x253c8
(NoMethodError)

And this confirms it:

class Song
#attr_reader :name, :artist, :duration
end

song = Song.new

puts song.name
puts song.artist
puts song.duration

puts song.fake

–output:—
r1test.rb:8: undefined method `name’ for #Song:0x25648 (NoMethodError)

On 9/1/07, 7stud *** [email protected] wrote:

puts song.duration
Nope. It’s just that an undefined instance variable is treated as
though it were nil. Try this on for size:

puts song.name
puts song.instance_variables

Logan C. wrote:

On 9/1/07, 7stud *** [email protected] wrote:

puts song.duration
Nope. It’s just that an undefined instance variable is treated as
though it were nil.

Then why isn’t song.fake treated as though it were nil?

Logan C. wrote:

Try this on for size:

puts song.name
puts song.instance_variables

lol. I looked up instance_variables in “Programming Ruby (2d ed)” and it
says:

“Note that simply defining an accessor does not create the corresponding
instance variables.”

That statement contradicts the statement I posted earlier on p. 31 of
the same book.

7stud – wrote:

Logan C. wrote:

Nope. It’s just that an undefined instance variable is treated as
though it were nil.

Then why isn’t song.fake treated as though it were nil?

song.fake isn’t an instance variable, it’s a method (well actually it’s
not,
it’s nothing, but if it did exists, it’d be a method).
attr_reader :duration creates the method duration, which returns the
instance variable @duration, even if the latter doesn’t exist yet.
song.fake throws an error because there is no method fake, independantly
of whether or not an instance variable @fake exists.
song.instance_variable_get “@fake” would return nil.

HTH,
Sebastian

Sebastian H. wrote:

attr_reader :duration creates the method duration, which returns the
instance variable @duration, even if the latter doesn’t exist yet.
song.fake throws an error because there is no method fake

Ok. Thanks for the explanation.

On Sun, 02 Sep 2007 08:53:59 +0900, 7stud *** wrote:

puts song.duration

puts song.fake

–output:—
r1test.rb:8: undefined method `name’ for #Song:0x25648 (NoMethodError)

There are two different things going on with attribute readers:

attr_reader :foo creates a method to access the instance variable
@foo.
When you get a NoMethodError, because there’s no such method.

Supposing you create an instance variable @bar in some method, such as
initailze, but have no attr_reader for it. You’ll still get a
NoMethodError because attr_reader wasn’t called to create a method for
it.

–Ken

On Sun, 02 Sep 2007 13:19:11 +0900, 7stud – wrote:

instance variables."

That statement contradicts the statement I posted earlier on p. 31 of
the same book.

For most purposes, you’ll never notice the difference. There’s only one
where you will, and that’s when you try to use the defined? keyword on
it:

class Foo
def foo
@foo=nil
end
def bar
defined? @foo
end
end

a=Foo.new => #Foo:0xb7c58b9c
a.bar => nil
a.foo => nil
a.bar => “instance-variable”

–Ken