In Depth: attr_reader/writer/accessor


#1

Can anyone explain exactly what happens when the interpreter interprets
attr_reader and its kin?

E.G. where is the method located (in which module, class) and what does
it do with the symbols in order to expand the method call into an
instance method of the calling class object?


#2

On Sun, Nov 23, 2008 at 4:45 PM, Matthew M. removed_email_address@domain.invalid
wrote:

Can anyone explain exactly what happens when the interpreter interprets
attr_reader and its kin?

E.G. where is the method located (in which module, class) and what does
it do with the symbols in order to expand the method call into an
instance method of the calling class object?

http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/241709

HTH
Michael G.


#3

Hi –

On Mon, 24 Nov 2008, Matthew M. wrote:

Can anyone explain exactly what happens when the interpreter interprets
attr_reader and its kin?

E.G. where is the method located (in which module, class) and what does
it do with the symbols in order to expand the method call into an
instance method of the calling class object?

attr_reader and friends are private instance methods of the class
Module:

Module.private_instance_methods(false).grep(/attr/)
=> [“attr_accessor”, “attr_writer”, “attr_reader”, “attr”]

which means that as long as self is an instance of Module or one of
its subclasses, those methods can be called. The Class class is a
subclass of Module, so instances of Class can execute those methods
too. That’s what’s happening when you do:

class C
attr_accessor :x
end

As for what it does: see Greg’s Ruby implementation, and also the
original C code which is in eval.c (look for the definition of
rb_attr). It basically calls rb_define_method, which is a general
method for adding methods to classes.

I used implementing attr_* as a metaprogramming exercise in a Ruby
course I taught last week, and it was very instructive. Amazing what
you can do in Ruby, without even getting terribly convoluted or
opaque.

David


#4

David A. Black wrote:

Hi –

On Mon, 24 Nov 2008, Matthew M. wrote:

Can anyone explain exactly what happens when the interpreter interprets
attr_reader and its kin?

E.G. where is the method located (in which module, class) and what does
it do with the symbols in order to expand the method call into an
instance method of the calling class object?

attr_reader and friends are private instance methods of the class
Module:

Module.private_instance_methods(false).grep(/attr/)
=> [“attr_accessor”, “attr_writer”, “attr_reader”, “attr”]

which means that as long as self is an instance of Module or one of
its subclasses, those methods can be called. The Class class is a
subclass of Module, so instances of Class can execute those methods
too. That’s what’s happening when you do:

class C
attr_accessor :x
end

As for what it does: see Greg’s Ruby implementation, and also the
original C code which is in eval.c (look for the definition of
rb_attr). It basically calls rb_define_method, which is a general
method for adding methods to classes.

I used implementing attr_* as a metaprogramming exercise in a Ruby
course I taught last week, and it was very instructive. Amazing what
you can do in Ruby, without even getting terribly convoluted or
opaque.

David

Not that I don’t appreciate the other responses but this is exactly what
I was looking for. Thank you for your help everyone. Also, David, can
you recommend any reference texts for Ruby that delve into this much
detail for other similar concepts. I’m nearly finished with Programming
Ruby: Pragmatic Programmers and I feel like I want a bit more.

Thanks!


#5

Not an answer to the OP’s question, but…

On Sun, Nov 23, 2008 at 5:27 PM, Michael G. removed_email_address@domain.invalid
wrote:

On Sun, Nov 23, 2008 at 4:45 PM, Matthew M. removed_email_address@domain.invalid wrote:

http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/241709

This implementation:

def new_attr_reader cl, sym
str = “def #{sym.to_s}; @#{sym.to_s}; end”
cl.class_eval str
end

is more dangerous than it needs to be. Instead, you can write:

def new_attr_reader(*args)
args.each { |e| define_method(e) { instance_variable_get("@#{e}") } }
end

Which allows for:

class A
new_attr_reader :a, :b, :c

def initialize
@a = 1
@b = 2
@c = 3
end
end

a = A.new
p [a.a, a.b, a.c] #=> [1, 2, 3]

Of course, substitute instance_variable_set for writers.


#6

Hi –

On Mon, 24 Nov 2008, Matthew M. wrote:

instance method of the calling class object?
too. That’s what’s happening when you do:
I used implementing attr_* as a metaprogramming exercise in a Ruby
detail for other similar concepts. I’m nearly finished with Programming
Ruby: Pragmatic Programmers and I feel like I want a bit more.

Sorry – this got lost in the inbox pipeline. I have an answer for
you, though: The Well-Grounded Rubyist (by me), due out in
March. See http://www.manning.com/black2. There’s no one-stop-shopping
source for all such stuff but I think you’ll find a good bit in there.

David


David A. Black / Ruby Power and Light, LLC
Ruby/Rails consulting & training: http://www.rubypal.com
Coming in 2009: The Well-Grounded Rubyist (http://manning.com/black2)

http://www.wishsight.com => Independent, social wishlist management!