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:
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
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
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-forum.com/\.
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)
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 = ?
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.
and has the side effect of assigning an @variable. It is totally possible to
implement #a= without having it assign a variable - it is in no way special.
All you do is force that method call by explicitly mentioning a receiver.
The second and third posts have made it clear for me. This is necessary
to allow local variables with the same name as instance variables. A
contrasting example from a statically typed language makes this more
clear (for me):
(Java)
public class Foo
private int x;
public void bar() {
int x = 2; // Very obviously a local variable
}
end
Since Ruby variables are allocated on first use, and Ruby has no
explicit variable declaration syntax, there would be no way to have a
local variable 'x' if an instance variable '@x' existed:
class Foo
attr_accessor :x
def bar
# If this were the same as self.x = 2, or @x = 2,
# it would not be possible to have a local variable 'x'?
x = 2
end
end
The second and third posts have made it clear for me. This is necessary
to allow local variables with the same name as instance variables. A
contrasting example from a statically typed language makes this more
clear (for me):
(Java)
public class Foo
private int x;
public void bar() {
int x = 2; // Very obviously a local variable
}
end
Since Ruby variables are allocated on first use, and Ruby has no
explicit variable declaration syntax, there would be no way to have a
local variable 'x' if an instance variable '@x' existed:
class Foo
attr_accessor :x
def bar
# If this were the same as self.x = 2, or @x = 2,
# it would not be possible to have a local variable 'x'?
x = 2
end
end
Remember, though, that
@x = 2
and
obj.x = 2 # where obj may or may not be self
have nothing to do with each other. As Florian said, obj.x = 2 is a method call (the method being x=).