From: "David A. Black" Date: 2009-02-08T04:58:20+09:00 Subject: Re: eval statement Hi -- On Sun, 8 Feb 2009, Mike Gold wrote: > > David A. Black: > >> The point about rb_method_missing (as the source of that error >> message) is interesting, though since it's be handled by a handler >> for non-existent methods, and within that handler it determines that >> it also isn't a local variable, I think it's reasonable to say that >> it can't tell -- or, perhaps more accurately, it *can* tell that it >> is neither a (viable) method call nor a variable, but it can't tell >> which you meant (hence the wording of the error message). > > No, I don't see a handler which determines that it isn't a local > variable. That was already decided by the parser which created a > method-call node because no "a = 1" syntax was found. The possibility > of a local variable was long since gone. > > p local_variables #=> [:a] > a = nil > > Is Ruby prescient? No, it's just the parser that determines locals. I'll stop trying to make that particular point, which is simpler than I'm managing to make it. All I'm really saying is that, one way or another, Ruby deems it appropriate to tell you that something that could, syntactically, be a local variable or a method call is in fact neither. To some extent I think that how it arrives at that conclusion is an implementation detail (though I'm reading the stuff you're saying about the implementation with great interest). > Take the 1.9 example again: > > eval("a = 3") > p local_variables #=> [] > p a #=> undefined local variable or method `a' > > But > > eval("a = 3") > p local_variables #=> [:a] > a = a > p a #=> 3 > > The parser looks for local assignment syntax and builds nodes > accordingly, then the interpreter runs. Somewhere along the line I got the impression you were saying that it was by parsing the argument-string, prior to executing eval, that Ruby figured out there was an 'a' local variable. Never mind. I think I'm back on course. >> >> There's also this interesting difference. In 1.8, given this code: >> >> eval("a=3") >> p a rescue p "undef" >> eval("p a") >> >> you get this output: >> >> "undef" >> 3 >> >> whereas in 1.9 the output for the same code is: >> >> "undef" >> -:3:in `eval': undefined local variable or method `a' >> >> So the business of having eval always return to the same scope seems >> to have been done away with. (I always thought of it as similar to the >> phenomenon of having to be drunk again to remember what you did when >> drunk :-) > > It's not really a scope issue; it's a parser issue. When we use the > same scope it fails in the same manner, > > eval("a=3", binding) > p a rescue p "undef" #=> "undef" > eval("p a", binding) #=> undefined local variable or method `a' > > I don't know if there is an official terminology--I would say these > two calls to 'binding' refer to the same scope while technically being > different bindings. It's reminiscent of what happens in a block: whatever exists already, by way of locals, is there, but anything created there does not survive the exit. (Reminiscent, not technically connected.) It's also a bit like the wrapper nature of things like method or float objects, where (for example) adding a singleton method to 1.2 doesn't do any good the next time you write 1.2. > Curiously, we can get the 1.8 behavior in 1.9 by using the same > binding, > > bind = binding > eval("a=3", bind) > p a rescue p "undef" #=> "undef" > eval("p a", bind) #=> 3 That's also similar to other wrapper behavior (like saving a particular float in a variable). It does seem like binding should be a proxy more than a wrapper, if that makes sense. David -- David A. Black / Ruby Power and Light, LLC Ruby/Rails consulting & training: http://www.rubypal.com Coming in 2009: The Well-Grounded Rubyist (http://manning.com/black2) http://www.wishsight.com => Independent, social wishlist management!