[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Why does attr_accessor in module require 'self.'?

Brian Hartin

4/27/2009 10:31:00 PM

Hi there,

When a class mixes in a module containing 'attr_accessor :foo', it must
then use 'self.foo = ...' instead of simply 'foo = ...'. While I prefer
'self.foo' for clarity's sake, I am stumped as to _why_ this is
required. For example:

module A
attr_accessor :a
end

class B
include A

def bar
a = "bar"
end

def baz
self.a = "baz"
end
end

module A
attr_accessor :a
end

class B
include A

def bar
a = "bar"
end

def baz
self.a = "baz"
end
end

irb(main):050:0> b = B.new
=> #<B:0x2db69cc>
irb(main):051:0> b.bar
=> "bar"
irb(main):052:0> b.a
=> nil
irb(main):053:0> b.baz
=> "baz"
irb(main):054:0> b.a
=> "baz"

Does anyone know why this is?

Thanks!

Brian Hartin
--
Posted via http://www.ruby-....

13 Answers

John Barnette

4/27/2009 10:40:00 PM

0

Hi,

On Apr 27, 2009, at 3:30 PM, Brian Hartin wrote:
> When a class mixes in a module containing 'attr_accessor :foo', it
> must
> then use 'self.foo = ...' instead of simply 'foo = ...'. While I
> prefer
> 'self.foo' for clarity's sake, I am stumped as to _why_ this is
> required. [snip]

It's because Ruby automatically creates local variables upon
assignment. Given a class with a method "foo":

class C
attr_accessor :a

def foo
a = 42 # this is a local variable assignment
self.a = 42 # this is a call to the "a=" method
end
end


~ j.


Joel VanderWerf

4/27/2009 10:48:00 PM

0

Brian Hartin wrote:
> Hi there,
>
> When a class mixes in a module containing 'attr_accessor :foo', it must
> then use 'self.foo = ...' instead of simply 'foo = ...'. While I prefer
> 'self.foo' for clarity's sake, I am stumped as to _why_ this is
> required. For example:
>
> module A
> attr_accessor :a
> end
>
> class B
> include A
>
> def bar
> a = "bar"
> end
>
> def baz
> self.a = "baz"
> end
> end

In B#bar, ruby's parser sees "a = ..." and assumes that "a" is local
variable, rather than attempting to call #a= (the writer method). This
has the advantage that, since local variables always "shadow" methods of
the same name, you can write code with the confidence that you are not
invoking some method defined in the class (or somewhere up the ancestor
chain) that you hadn't noticed. For one thing, this makes it easier to
write code that knows as little as possible about its context, and hence
can be shared around by Module#include or even copy-n-paste.

It is, however, a disadvantage for DSL design, but that's another story...

--
vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

7stud --

4/28/2009 12:26:00 PM

0

John Barnette wrote:
>
> It's because Ruby automatically creates local variables upon
> assignment. Given a class with a method "foo":
>

Can attr_accessor ever apply to variables that don't begin with @?



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

Ryan Davis

4/28/2009 7:13:00 PM

0


On Apr 28, 2009, at 05:26 , 7stud -- wrote:

> John Barnette wrote:
>>
>> It's because Ruby automatically creates local variables upon
>> assignment. Given a class with a method "foo":
>>
>
> Can attr_accessor ever apply to variables that don't begin with @?

no, otherwise it'd be named something else.

7stud --

4/28/2009 9:35:00 PM

0

Ryan Davis wrote:
> On Apr 28, 2009, at 05:26 , 7stud -- wrote:
>
>> John Barnette wrote:
>>>
>>> It's because Ruby automatically creates local variables upon
>>> assignment. Given a class with a method "foo":
>>>
>>
>> Can attr_accessor ever apply to variables that don't begin with @?
>
> no, otherwise it'd be named something else.

Well, then what's all this talk about "the parser sees this, and the
parser does that". The op never tries to access an instance variable in
the classs, so the fact that a call to attr_accessor is in the class is
irrelevant. End of story.
--
Posted via http://www.ruby-....

7stud --

4/28/2009 10:14:00 PM

0

7stud -- wrote:
> Ryan Davis wrote:
>> On Apr 28, 2009, at 05:26 , 7stud -- wrote:
>>
>>> John Barnette wrote:
>>>>
>>>> It's because Ruby automatically creates local variables upon
>>>> assignment. Given a class with a method "foo":
>>>>
>>>
>>> Can attr_accessor ever apply to variables that don't begin with @?
>>
>> no, otherwise it'd be named something else.
>
> Well, then what's all this talk about "the parser sees this, and the
> parser does that". The op never tries to access an instance variable in
> the classs, so the fact that a call to attr_accessor is in the class is
> irrelevant. End of story.

Hmm...not quite:

class B
end

b = B.new
puts b.a

--output:--
undefined method `a' for #<B:0x253c8> (NoMethodError)


class B
attr_accessor :a
end

b = B.new
puts b.a

nil

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

7stud --

4/28/2009 11:17:00 PM

0

7stud -- wrote:
>> Well, then what's all this talk about "the parser sees this, and the
>> parser does that".

If you do this:

class B
def a
@a
end

def bar
"bar"
end

def baz
self.a = "baz"
end
end

b = B.new
puts b.bar
puts b.a
puts b.baz

--output:--
bar
nil
'baz': undefined method `a=' for #<B:0x24fe0> (NoMethodError)

1) b.a returns nil because the 'a' method exists, but the 'a' method
tries to return a non-existent instance variable @a.

2) The error message is due to the fact that self.a tries to access a
method called a=, which in this class doesn't exist.

If you add the setter method, a=, then the error message goes away:

class B
def a
@a
end

def a=(val)
@a = val
end

def bar
"bar"
end

def baz
self.a = "baz"
end
end

b = B.new
puts b.bar
puts b.a
puts b.baz

--output:--
bar
nil
baz
baz

Note that 'a =' doesn't appear anywhere in the code. Adding 'a =' in
the body of a method doesn't change anything:

class B
def a
@a
end

def a=(val)
@a = val
end

def bar
a = "bar" #<----****
end

def baz
self.a = "baz"
end

def foo
a = 10
end
end

b = B.new
puts b.bar
puts b.a
puts b.baz
puts b.a


--output:--
bar
nil
baz
baz


All of which I guess has nothing to do with the op's question. The op
correctly identified that self.a = "baz" calls the a= method, but that a
= "bar" does not. I guess I would pose this question to the op: when
have you ever been able to access the a= method in a class without using
the format some_obj.a = ?



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

7stud --

4/28/2009 11:35:00 PM

0

7stud -- wrote:
> class B
> def a
> @a
> end
>
> def a=(val)
> @a = val
> end
>
> def bar
> a = "bar" #<----****
> end
>
> def baz
> self.a = "baz"
> end
>
> def foo
> a = 10
> end
> end
>
> b = B.new
> puts b.bar
> puts b.a
> puts b.baz
> puts b.a
>
>
> --output:--
> bar
> nil
> baz
> baz
>
>
> All of which I guess has nothing to do with the op's question. The op
> correctly identified that self.a = "baz" calls the a= method, but that a
> = "bar" does not. I guess I would pose this question to the op: when
> have you ever been able to access the a= method in a class without using
> the format some_obj.a = ?

I guess the idea here:

> def bar
> a = "bar" #<----****
> end
>
> def baz
> self.a = "baz"
> end

is that when you call a method without a receiver, self is implied. So
the bar method would be equivalent to:

> def bar
> self. a = "bar" #<----****
> end
>

Therefore bar and baz have the same format and should do the same thing.
But...

John Barnette wrote:
> Ruby automatically creates local variables upon
> assignment.

which might be explained further(though perhaps wrongly) by saying:
before ruby can attach 'self.' to the front of 'a' in the bar method:

> def bar
> a = "bar"
> end

the parser tells ruby that it should create a local variable called 'a'
instead and assign it the value on the right of the equals sign. As a
result unadorned names, for example 'a' vs. 'obj.a', that appear to the
left of an equals sign cause ruby to create a local variable and assign
the local variable the value to the right of the equals sign.

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

Shaun Keller

4/29/2009 8:12:00 AM

0

The short answer would be that

a = 'bar'

is a local variable assignment, whereas

self.a = 'bar'

is an instance variable assignment, like @a
--
Posted via http://www.ruby-....

Ryan Davis

4/29/2009 8:36:00 AM

0


On Apr 28, 2009, at 16:34 , 7stud -- wrote:

> I guess the idea here:
>
>> def bar
>> a = "bar" #<----****
>> end
>>
>> def baz
>> self.a = "baz"
>> end
>
> is that when you call a method without a receiver, self is implied.
> So
> the bar method would be equivalent to:
>
>> def bar
>> self. a = "bar" #<----****
>> end
>>
>
> Therefore bar and baz have the same format and should do the same
> thing.
> But...

no. consider local variable assignment to be higher precedence than
message send.

var = val

will ALWAYS be local variable assignment, even if you have #var=.