From: Mike Gold Date: 2009-02-08T00:42:52+09:00 Subject: Re: eval statement David A. Black: > > p local_variables #=> ["a"] > > p a #=> undefined local variable or method `a' > > > > We see that the local exists, but because the parser has not seen > > the "a = ..." syntax, we can't access it. > > In 1.9 you get: > > [] > -:3:in `
': undefined local variable or method `a' for > main:Object (NameError) > > so I guess that's been changed. Yes, in 1.9 the local table is inside the parser, and a new parser is created for each eval. In 1.8 the local table is static (as well as the parser). > 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. 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. > > 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. 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 -- Posted via http://www.ruby-forum.com/.