Eval statement

Trying to switch a project of mine from python to ruby. Love ruby so
far, but I’m finding that the eval statement is a bit more difficult to
use than python’s exec statement. Here is one of the problems I’m
having, RUBY_VERSION=1.9.1

a = 1
eval(‘a=2’)
puts a

This will print out ‘2’, as I want. However if I remove the first line,

eval(‘a=2’)
puts a

r.rb:2:in <main>': undefined local variable or methoda’ for
main:Object (NameError)

Now if in the first case eval can change a variable in its scope, why
can’t it also create a variable in that same scope? I may also not be
totally clear on the way ruby handles scoping, which might be part of
what I am having trouble understanding.

Any help understanding the eval statement would be appreciated. I will
probably have more questions about it, but I’ll leave at this for now.

thanks,
-Jonathan

Jonathan W. schrieb:

what I am having trouble understanding.

Any help understanding the eval statement would be appreciated. I will
probably have more questions about it, but I’ll leave at this for now.

thanks,
-Jonathan
why do you want to use eval?
eval is evil and in most cases not needed in Ruby

why do you want to use eval?
eval is evil and in most cases not needed in Ruby

I want my program to run user-supplied ruby code, and eval is the only
thing I know of that can do this. If there is a better way I would be
willing to try it. I know in python that the exec statement is
considered ‘evil’, but all that means is you have to be careful.

Jonathan W. wrote:

a = 1
eval(‘a=2’)
puts a

This will print out ‘2’, as I want. However if I remove the first line,

eval(‘a=2’)
puts a

The thing to remember is that local variables are always determined at
parse time.

The contents of ‘a=2’ is not seen by the parser when the file is read,
so in the second case the ‘a’ in ‘puts a’ is determined to be a method
call: “call method ‘a’, then call method puts”.

Constants and instance variables are different, as they are determined
by their naming scheme and therefore behave more as you expected.

irb(main):001:0> eval("@a = 2")
=> 2
irb(main):002:0> @a
=> 2
irb(main):003:0> eval(“X = 3”)
=> 3
irb(main):004:0> X
=> 3

On Feb 6, 2009, at 1:52 PM, Jonathan W. wrote:

Now if in the first case eval can change a variable in its scope, why
can’t it also create a variable in that same scope? I may also not be
totally clear on the way ruby handles scoping, which might be part of
what I am having trouble understanding.

Because eval creates a new nested scope rather than sharing the
enclosing scope.

Variable visibility between nested scopes is like a one-way mirror:
you can manipulate variables created in a parent scope but you can not
see or manipulate variables created in a ‘child’ scope.

Mike G. schrieb:

The thing to remember is that local variables are always determined at
=> 2
irb(main):002:0> @a
=> 2
irb(main):003:0> eval(“X = 3”)
=> 3
irb(main):004:0> X
=> 3

be careful when using eval in irb. It can lead to hasty conclusions (is
this correct english? Google Translate sucks =D) which are not correct
in a pure ruby environment (because under the hood irb uses lots of evil
evals)

Hi –

On Sat, 7 Feb 2009, Jonathan W. wrote:

why do you want to use eval?
eval is evil and in most cases not needed in Ruby

I want my program to run user-supplied ruby code, and eval is the only
thing I know of that can do this. If there is a better way I would be
willing to try it. I know in python that the exec statement is
considered ‘evil’, but all that means is you have to be careful.

Yes, but what does that mean? :slight_smile:

David


David A. Black / Ruby Power and Light, LLC
Ruby/Rails consulting & training: http://www.rubypal.com
Coming in 2009: The Well-Grounded Rubyist (The Well-Grounded Rubyist)

http://www.wishsight.com => Independent, social wishlist management!

Because eval creates a new nested scope rather than sharing the
enclosing scope.

Variable visibility between nested scopes is like a one-way mirror:
you can manipulate variables created in a parent scope but you can not
see or manipulate variables created in a ‘child’ scope.

Ok, I see that now, good to know. Now I have another question. I want
to be able to create an arbitrary number of ‘clean’ bindings in which I
can run ruby code. Basically I want the user to be able to supply an
unspecified number of ruby files, all of which will get run, and not
have to worry about namespace collisions. Additionally I want access to
the scopes that those files were executed in after they are done. I
know I can create a binding from my current scope, but if I put anything
in it, it can get modified when I do my_binding.eval.

In python this was quite simple by passing clean dictionaries to the
exec statement, but perhaps I will have to rethink my design :frowning:

thanks,
-Jonathan

On Fri, Feb 6, 2009 at 11:55 AM, Jonathan W. [email protected]
wrote:

can run ruby code. Basically I want the user to be able to supply an
unspecified number of ruby files, all of which will get run, and not
have to worry about namespace collisions. Additionally I want access to
the scopes that those files were executed in after they are done. I
know I can create a binding from my current scope, but if I put anything
in it, it can get modified when I do my_binding.eval.

You can get a binding from any object that has a method to tell you
its binding. Something like this (off the top of my head) might work:

class ExecutionContext
private_class_method :new

@@contexts = {}

def self.
@@contexts[key]
end

def self.new_binding(key)
new(key).binding
end

def initialize(key)
raise KeyError if @@contexts[key]
@@contexts[key] = self
end

def get_binding
binding
end
end

So, when you want a new binding to use, you call
ExecutionContext.new_binding(key), and to get back the a binding used
previously, you call ExecutionContext[key].get_binding, where “key” is
the key given when you called new_binding to generate the binding.

But while these are mostly “fresh” bindings, they are nothing at all
like safe sandboxes. You may need something like this:
http://github.com/why/sandbox/tree/master

Hi –

On Sat, 7 Feb 2009, Mike G. wrote:

The thing to remember is that local variables are always determined at
parse time.

The contents of ‘a=2’ is not seen by the parser when the file is read,
so in the second case the ‘a’ in ‘puts a’ is determined to be a method
call: “call method ‘a’, then call method puts”.

Actually it can’t tell whether it’s a method or a variable, so you
get:

undefined local variable or method `a’ for main:Object (NameError)

=> 3
They’re that way because of how they’re scoped, but the assignments
themselves are handled by eval the same way as the local ones; that
is, there’s no extra information available prior to the execution.

David


David A. Black / Ruby Power and Light, LLC
Ruby/Rails consulting & training: http://www.rubypal.com
Coming in 2009: The Well-Grounded Rubyist (The Well-Grounded Rubyist)

http://www.wishsight.com => Independent, social wishlist management!

Christopher D. wrote:

On Fri, Feb 6, 2009 at 11:55 AM, Jonathan W. [email protected]
wrote:

can run ruby code. Basically I want the user to be able to supply an
unspecified number of ruby files, all of which will get run, and not
have to worry about namespace collisions. Additionally I want access to
the scopes that those files were executed in after they are done. I
know I can create a binding from my current scope, but if I put anything
in it, it can get modified when I do my_binding.eval.

You can get a binding from any object that has a method to tell you
its binding. Something like this (off the top of my head) might work:

class ExecutionContext
private_class_method :new

@@contexts = {}

def self.
@@contexts[key]
end

def self.new_binding(key)
new(key).binding
end

def initialize(key)
raise KeyError if @@contexts[key]
@@contexts[key] = self
end

def get_binding
binding
end
end

So, when you want a new binding to use, you call
ExecutionContext.new_binding(key), and to get back the a binding used
previously, you call ExecutionContext[key].get_binding, where “key” is
the key given when you called new_binding to generate the binding.

But while these are mostly “fresh” bindings, they are nothing at all
like safe sandboxes. You may need something like this:
http://github.com/why/sandbox/tree/master

Interesting. Someone else has shown me a similar way of getting a fresh
context. Do you know what exactly about it is unlike a sandbox? I know
that with this approach that code that I run can use the require
statement and it will drop such files into my scope, but are there any
other sort of problems?

Are there any plans for ruby to support a sandboxed eval like I can get
in python? I might be willing to contribute such a thing if it could
get added into the standard interpreter.

thanks

David A. Black wrote:

Hi –

On Sat, 7 Feb 2009, Mike G. wrote:

The thing to remember is that local variables are always determined at
parse time.

The contents of ‘a=2’ is not seen by the parser when the file is read,
so in the second case the ‘a’ in ‘puts a’ is determined to be a method
call: “call method ‘a’, then call method puts”.

Actually it can’t tell whether it’s a method or a variable, so you
get:

undefined local variable or method `a’ for main:Object (NameError)

No, that error message comes from rb_method_missing(), i.e., it was
determined to be a method call. Presumably it is worded that way for
the user’s benefit, in case there was a misspelling or some such.
Locals are determined by the parser; method lookup is done when no such
local exists.

They’re that way because of how they’re scoped, but the assignments
themselves are handled by eval the same way as the local ones; that
is, there’s no extra information available prior to the execution.

Locals are not handled in the same way. The local assignment syntax is
subject to special examination by the parser. This does not happen for
instance variables and globals. Again, it is the parser that determines
locals. If all assignments were the same, this would print ‘3’:

eval(“a = 3”, binding)
puts a

Pickaxe gives this example:

def a
print “Function ‘a’ called\n”
99
end

for i in 1…2
if i == 2
print “a=”, a, “\n”
else
a = 1
print “a=”, a, “\n”
end
end

produces:

a=1
Function ‘a’ called
a=99

On Fri, Feb 6, 2009 at 1:46 PM, Jonathan W. [email protected]
wrote:

You can get a binding from any object that has a method to tell you

binding

like safe sandboxes. You may need something like this:
http://github.com/why/sandbox/tree/master

Interesting. Someone else has shown me a similar way of getting a fresh
context. Do you know what exactly about it is unlike a sandbox?

The code being eval’d can, as I understand, do anything that a method
on the object providing the binding could do, including, e.g., using
ObjectSpace to mess with any object in the current interpreter
instance, even if it is out of scope of the binding.

Are there any plans for ruby to support a sandboxed eval like I can get
in python?

I think the use of the trusted/untrusted distinction with $SAFE levels
in Ruby 1.9 may be able to do some, perhaps all, of what you want, but
I haven’t done any work with it (just read the description in the Beta
of the new edition of Programming Ruby), so I can’t really say. It’s
not an eval-specific sandbox, though.

Why is eval evil?

Blog: http://random8.zenunit.com/
Learn rails: http://sensei.zenunit.com/

Mike G. wrote:
If all assignments were the same, this would print ‘3’:

eval(“a = 3”, binding)
puts a

Or even better,

eval(“a = 3”, binding)
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.

badboy [email protected] writes:

This will print out ‘2’, as I want. However if I remove the first line,
totally clear on the way ruby handles scoping, which might be part of
what I am having trouble understanding.

Any help understanding the eval statement would be appreciated. I will
probably have more questions about it, but I’ll leave at this for now.

thanks,
-Jonathan
why do you want to use eval?
eval is evil and in most cases not needed in Ruby

Why are you saying that eval is evil?

In know that in Common Lisp, EVAL has properties that make its use
dubious in most cases. Mostly it’s because it works in the global
environment.

But this is not the case of eval in Ruby. Since there’s no compiler,
they can execute eval in the local lexical environment. So is there
remaining any evilness I don’t know?

irb(main):001:0> (def f(e)
(a = 42)
(eval e)
(eval e)
end)
nil
irb(main):006:0> (f “puts a”)
42
42
nil
irb(main):007:0> (f “puts a ; e="puts a+1"”)
42
43
nil

Hi –

On Sat, 7 Feb 2009, Mike G. wrote:

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 <main>': undefined local variable or method a’ for
main:Object (NameError)

so I guess that’s been changed. 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).

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 :slight_smile:

David


David A. Black / Ruby Power and Light, LLC
Ruby/Rails consulting & training: http://www.rubypal.com
Coming in 2009: The Well-Grounded Rubyist (The Well-Grounded Rubyist)

http://www.wishsight.com => Independent, social wishlist management!

On 2/6/09, Pascal J. Bourguignon [email protected] wrote:

puts a
Now if in the first case eval can change a variable in its scope, why
eval is evil and in most cases not needed in Ruby

Why are you saying that eval is evil?

In know that in Common Lisp, EVAL has properties that make its use
dubious in most cases. Mostly it’s because it works in the global
environment.

But this is not the case of eval in Ruby. Since there’s no compiler,
they can execute eval in the local lexical environment. So is there
remaining any evilness I don’t know?

Without taking additional special care, restricting eval to the to a
particular binding doesn’t contain it very much. eval can, unless
something is done to stop it, get access to every Object in the top
level environment.

For example try running this in irb:

hash = Hash.new
object = Object.new
def object.get_binding
binding
end
b = object.get_binding
eval(‘ObjectSpace.each_object {|o| next if o.frozen?; begin def
o.inspect; “pwned”; end; rescue TypeError; end}’,a)
hash #=>pwned

If you run untrusted code in eval without being extra careful, it can
reach out of the binding its in and stomp over other objects, even
outside of that binding.

Pascal J. Bourguignon wrote:

puts a
Now if in the first case eval can change a variable in its scope,
eval is evil and in most cases not needed in Ruby

irb(main):007:0> (f "puts a ; e=“puts a+1"”)
42
43
nil

C:>irb --prompt xmp
(def f(e)
(a = 42)
(eval e)
(eval e)
end)
==>nil
(f “puts a ; e=‘puts a+1’”)
42
43
==>nil
(f “p a ; e=‘p a+1’”)
42
43
==>nil

Christopher D. [email protected] writes:

dubious in most cases. Mostly it’s because it works in the global

hash #=>pwned

If you run untrusted code in eval without being extra careful, it can
reach out of the binding its in and stomp over other objects, even
outside of that binding.

Ok. In CL we say EVAL is evil because it cannot do some things, and in
Ruby you say it’s evil because it can. How interesting…

Of couse, when you execute dynamic code, you must trust the source of
that code. This doesn’t “evilize” the mechanism to execute it.