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?

···

--
Posted via http://www.ruby-forum.com/.

# "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

···

From: 7stud 7stud [mailto:dolgun@excite.com]
------------------------------------------------------------------------
     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:dolgun@excite.com]
# "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?

···

--
Posted via http://www.ruby-forum.com/\.

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

···

From: 7stud *** [mailto:dolgun@excite.com]
#
# 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

Ok. Thanks.

···

--
Posted via http://www.ruby-forum.com/.

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)

···

------------------------------------------
Daniel Brumbaugh Keeney
Devi Web Development
Devi.WebMaster@gMail.com

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)

···

--
Posted via http://www.ruby-forum.com/.

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)

···

--
Posted via http://www.ruby-forum.com/.

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

···

On 9/1/07, 7stud *** <dolgun@excite.com> wrote:

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

Logan Capaldo wrote:

···

On 9/1/07, 7stud *** <dolgun@excite.com> 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?

--
Posted via http://www.ruby-forum.com/\.

Logan Capaldo 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.

···

--
Posted via http://www.ruby-forum.com/\.

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 08:53:59 +0900, 7stud *** wrote:

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)

--
Ken Bloom. PhD candidate. Linguistic Cognition Laboratory.
Department of Computer Science. Illinois Institute of Technology.
http://www.iit.edu/~kbloom1/

7stud -- wrote:

Logan Capaldo 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

···

--
Jabber: sepp2k@jabber.org
ICQ: 205544826

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

···

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

Logan Capaldo 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.

--
Ken Bloom. PhD candidate. Linguistic Cognition Laboratory.
Department of Computer Science. Illinois Institute of Technology.
http://www.iit.edu/~kbloom1/

Sebastian Hungerecker 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.

···

--
Posted via http://www.ruby-forum.com/\.