Politics, Programming and Possibilities
4 Jan
This was a weird Ruby gotcha that my coworker, Paul Jones, discovered. Here’s a test class to show the point:
class T
private
def l=(val); puts val end
def l; 1 end
public
def m=(val); self.l=val end
def m; self.l end
end
irb> t.m=1
1
=> 1
irb> t.m
NoMethodError: private method `l' called for #
Anyone know why this is the case?
Update: Perhaps I should clarify. I was expecting the “m=” method to work as it did, but I did not expect the NoMethodError when calling “m”. A better question might be, “Why the discrepency?”
7 Responses for "Ruby Gotcha—Private Assignment Methods not so Private"
Self references the current object. There is no magic to that. Its the same as an instance variable pointing to the object. Everything you call on self goes through the public interface of the object.
def m; l; end should work
Turns out private methods, by definition, *cannot* have an explicit receiver. Regardless of whether you’re calling it from a place that’s technically “in scope.”
Actually, I think I didn’t answer your question. Please disregard!
tobi: Perhaps I should have named my post, “self referenced private method is inaccessible” or something to that effect.
The ‘def m; l; end’ suggestion you have there is precisely what I expected to work, which does *not* work.
I’m with Tobi on this one, his code works for me. The discrepency is due to the fact that assignment needs a receiver otherwise it’s just assignment to a local variable.
Say you have “def m=(val); l = val; end” then the l variable is simply a local variable, to make it into a method call we need the receiver (self).
Now usually you wouldn’t be able to call a private method with an explicit reciever but with assignment Ruby goes out of it’s way to make sure you can.
Jacob:
My mistake. “def m; l; end” does work. I was pointing you in the wrong direction.
I’m kind of following you at this point, but maybe you could expound a bit on this particular aspect of the “discrepency”:
Now suppose t = T.new:
If I understand you correctly, you’re saying this is an anomaly that Ruby intentionally affords us… but why? Why shouldn’t we have to declare “l=” as a public method (or at the least, a protected method) so that “m=” can call “self.l=”?
It just seems like a weird exception to the rules to me. But obviously that’s the way it is, so I’ll adjust
Duane asked:
Why shouldn’t we have to declare “l=” as a public method (or at the least, a protected method) so that “m=” can call “self.l=”?
I’m no Ruby guru, but my guess is that then we’d have no way of creating private assignment methods, maybe that’s what “they” are trying to tell us
I agree that it’s a weird exception though I don’t know how it could be made any more elegant with the current Ruby syntax.
Leave a reply