From: mrilu Date: 2000-04-01T02:45:11+02:00 Subject: [ruby-talk:02319] Re: Question about attribute writers On Fri, 31 Mar 2000, Clemens Hintze wrote: > Dave Thomas writes: > class Fred > def age > @age > end > def age=(val) > @age = val > end > def ageInMonths > age * 12 > end > def ageInMonths=(val) > age = val / 12 > end > def initialize(age) > @age = age > end > end > > f = Fred.new(10) > p f.age > p f.ageInMonths > f.ageInMonths = 300 > p f.age > >I get > > 10 > 120 > 10 > > The reason is that the assignment > > > > age = val/12 > > > > in Fred#ageInMonths= is creating a local variable 'age', rather than > > invoking the age= method. > > This seems inconsistent with the fact that > > > > age / 12 > > > > in Fred#ageInMonths is correctly using the attribute reading > > function. > > Is this the expected behavior? I can't expect it even if I somebody says there's a trick in here. So following will try to give some light what I expected. Clemens: > At least I would expect it! It is like answered in your FAQ! How does > Ruby determine what a variable is? It is really stright-forward, IMHO. > > Look if there was an assignment before > yes => compile a variable access > no => compile a method call. > > That means, the compiler seems to prefer to compile variable access > over compiling method calls. So > > age / 12 > > would let the interpreter look whether if has already seen a > assignment to a local variable. As it didn't it compile a method call! > So Fred#age would be called. However Agreed. > age = val / 12 > > looks like an assignment. That means variable access! As Ruby prefer > this, why should the compiler try to compile method call here? Disagreed. If I look your excerpt from FAQ I see "if there was". And before this line I haven't seen assignment to age. On this line interpreter sees assignment, but that doesn't qualify your requirement of "was assigned already". But the requirement is fuzzy itself at least in these ways - assignment to local variable / assignment to accessors - "before" at compile time (at parsing) / at runtime (hopefully not) So if we think that requirement is (I reformulate it a little): "Code is interpreted as variable access if at compile time we have already seen assignment to local variable in current scope". I think we face a problem here. With this requirement we can't ever assign local variable, thus create one. So I think we have to loose up a little. "When we have to test whether code is interpreted as a instance call or access to a local variable, local variable wins: 1) at write access (assignment) always (to be able to create local variables) 2) at read access if we have seen 1) earlier in local scope. " Now the problem is that we can't ever call age=()-method inside class declaration. val = age * 2 # 2) condition not met, so calling age() age = val / 2 # 1) no condition, so create new local variable val = age * 2 # 2) condition met at previous row, # so accessing local variable age = val / 2 # 1) no condition, so accessing local variable > But, however, if it was written as > > self.age = val / 12 There was a catch in the last paragraph. We can't call age=() directly, but with self I think we should be able to say we really mean self.age() at read access and self.age=() at write access. > then Ruby is not able to think of an variable access here, as this > syntax is invalid at that point! So it will compile a method call to > Fred#age= I'd like to clarify this a little. I think self.age can't be tried to understand as a local variable access because it is no local variable. Not because it is not valid syntax (it is I guess, there is just no syntax to interpret it as local variable, but there is syntax to interpret it as self's method). One additional question: why we need age= at all in Dave's example if we have declared age as it is. I would expect age() = val / 12 --> @age = val / 12 Then it's up to definition whether age = val / 12 means age() = val / 12. > Sorry for my confusing explanation. But I hope you got my point > anyway. When I read your mail I was full of understanding. Now that I wrote this everything fades away... :)