Getter methods can be used without an explicit receiver unless there is a local variable with the same name:
class A; attr_reader :foo end
A.new.instance_eval do
@foo = :foo
p foo
end
# => :foo
This will not hold when there is a local variable with the same name, due to the principle that interpretation as a local variable has priority than as a method call whenever there is an ambiguity.
class A; attr_reader :foo end
A.new.instance_eval do
foo = :bar
@foo = :foo
p foo
end
# => :bar
However, setter methods cannot be used without an explicit receiver even when a local variable with the same name is not assigned prior to the expression in question:
class A; attr_writer :foo end
A.new.instance_eval do
foo = :foo # <= No local variable named `foo` has been assigned before this point
p @foo
end
# => nil
How is this "anti-private" property of setter method justified?
If ruby interpreted your assignment in your last statement as an assignment to
self
, you would have no way left to set a local variable.The way it is leaves no ambiguity for the interpreter to deal with: assignments without
self
are always local variables, assignments to self are always trying to use a writer on the object.If it were the other way around
The interpreter would have to look up the contexts writer methods and assign it via the writer if there is one, which almost certainly would have a negative impact on performance
It would also leave the programmer with the rather stupid task to find out every setter method of the context he's in before assigning local variables to make absolutely sure he does not unintentionally use a setter.
Also, your question reads:
If it were the other way around, you could not assign a local variable with the same name prior to the expression in question, because the assignment would use the setter (as stated in the first paragraph of this answer)
Concerning the implementation / the access to variables the attribute methods use: Getter and Setters work with instance variables. So, for example
attr_accessor
actually defines something like this:So, the attribute is declared as a instance variable and not as a local variable, why should the programmer be able to assign it like a local variable? This would leave the wrong impression that you could assign instance variables of an object via assigning local variables. If ruby would do this, it would almost certainly lead to a serious memory management problem. To make it short:
foo = 'bar'
and@foo = 'bar'
are not the same, and exactly because theattr
methods use@foo = 'bar'
, you can not call them via usingfoo = 'bar'
.I think @sawa finally clarified what is meant by "anti-private".
sawa's comment:
I was confused, apparently along with all the other commenters, because "anti-private" and "against private" aren't standard terminology, nor was the meaning immediately obvious.
I think the meaning of the original question is: "Since setters require an explicit receiver, and
private
forbids explicit receivers, how can I call aprivate
setter?" In other words, "anti-private" means "incompatible withprivate
", or "unusable withprivate
".Jörg W Mittag eloquently explains an exception to the normal
private
rules. Basically, setters can be called onself
even if they are private, because there's no other way to call them (unless you use the cumbersomesend
).So, a setter's requirement of an explicit receiver is perfectly compatible with the setter being
private
, only because of the exception to the rule.Beat Richartz's answer is pretty complete already, but I want to highlight one point about the behavior you're proposing.
In your question you have this sample code:
You are proposing that the assignment call the setter method. And you want this to happen if the local-variable
foo
hasn't been assigned yet.But what syntax would you use to assign the local before that point?
If the receiverless assignment
foo = :foo
means call the setter (when it exists), you'd need yet another syntax construct to mean "assign this local-variable, disregarding whether there is a setter".I honestly do want to hear your proposal (I'm not being sarcastic) if you have one. It would be interesting to hear alternative views on language design.
I'm not saying your way would be necessarily "worse" than the current ruby way. But at some point a language designer has to decide default behaviors for ambiguous situations, and Matz decided that receiverless assignment assigns the local.