Making sense of the various Ruby "eval"s


#1

Hi all,

Unlike other dynamic languages I’m familiar with (Perl, Lisp), Ruby has
more than one form of ‘eval’, which is quite confusing for Ruby nubies
like myself. I’m trying to make some sense of all the possibilities:

  • Kernel#eval -

This one I (almost) understand. It behaves like Perl’s eval, with the
difference that it can take a ‘binding’ which is another Object, or
Proc. In case of the Object I understand that the code 'eval’ed can
access the Object’s instance vars. But how does that work with a Proc as
a binding ?

  • Object#instance_eval -

Is obj.instance_eval(“blah”) exactly the same as eval(“blah”, obj) ? If
the answer to this question is positive, then the string version of
instance_eval is clear. But what about its block version ? How does that
work ? Are the contents of the block just treated as a string ?

  • Module#class_eval -

With its synonym module_eval: very similar to Object#instance_eval, just
that all methods are added to a class and not to an object, right ?

Thanks in advance


#2

“E” == Eli B. removed_email_address@domain.invalid writes:

E> - Kernel#eval -

it’s the evil eval, forget it :slight_smile:

E> - Object#instance_eval -

E> Is obj.instance_eval(“blah”) exactly the same as eval(“blah”, obj) ?

You can give only a Proc/Binding to the evil eval

E> work ? Are the contents of the block just treated as a string ?

no, the block is executed with self = object

E> - Module#class_eval -

moulon% cat b.rb
#!/usr/bin/ruby
class A
end

A.instance_eval {
p self
def a
puts “A::a”
end
}

A.module_eval {
p self
def a
puts “A#a”
end
}

A.a
A.new.a
moulon%

moulon% ./b.rb
A
A
A::a
A#a
moulon%

Guy Decoux


#3

ts wrote:

“E” == Eli B. removed_email_address@domain.invalid writes:

E> - Kernel#eval -

it’s the evil eval, forget it :slight_smile:

Forget Kernel#eval or the string version of any #eval ? The first maybe,
but the second is what allows code generation on-the-fly.

E> - Object#instance_eval -

E> Is obj.instance_eval(“blah”) exactly the same as eval(“blah”, obj) ?

You can give only a Proc/Binding to the evil eval

E> work ? Are the contents of the block just treated as a string ?

no, the block is executed with self = object

And in the string version, what is ‘self’ ?
I’m struggling to fully understand the difference between the block and
the string versions ?

E> - Module#class_eval -

moulon% cat b.rb
#!/usr/bin/ruby
class A
end

OK I think I understand: instance_eval adds instance methods to a class,
and class/module_eval adds class methods to a class. But also
instance_eval can be called on any object, but class_eval can’t (it can
be called only on class / module objects). Correct ?


#4

“E” == Eli B. removed_email_address@domain.invalid writes:

E> I’m struggling to fully understand the difference between the block
and
E> the string versions ?

the string version is evil :slight_smile:

E> OK I think I understand: instance_eval adds instance methods to a
class,

instance_eval add singleton methods, this is why you can use it with
any
objects (not only class, modules).

E> and class/module_eval adds class methods to a class. But also

no, add instance method for a class. This is why you can use it only
with
a class, module.

E> instance_eval can be called on any object, but class_eval can’t (it
can
E> be called only on class / module objects). Correct ?

yes.

Guy Decoux


#5

“E” == Eli B. removed_email_address@domain.invalid writes:

E> What have I missed ?

The evilness of eval.

Guy Decoux


#6

ts wrote:

“E” == Eli B. removed_email_address@domain.invalid writes:

E> I’m struggling to fully understand the difference between the block
and
E> the string versions ?

the string version is evil :slight_smile:

It may be evil but it is necessary. Correct me if I am wrong, but this
is how I see it - the string version of eval is the only way to
differentiate between “evaluation time” and “execution time”. Example:

name = ‘“Mike”’
evaltime = eval “lambda {name = ‘Jane’; puts #{name}}”;
runtime = eval “lambda {name = ‘Jane’; puts name}”;

evaltime.call
runtime.call

==> Mike
==> Jane

Unless I’m misunderstanding something, this can be only done with the
string version of eval. Additionally, stitching pieces of code together,
like this:

var = ‘“Jane”’
estr = “lambda {name =” + var + “; puts name}”

runtime = eval estr
runtime.call

Can also be done only with the string version.

The way I see it, the block version is simply a convenience, making the
code cleaner. It is similar to wrapping a string into a single
(non-interpolating) quote:

class Ab
end

boor = Ab.new

boor.instance_eval {
p “using block”
def a
puts “Ab::a”
end
}

boor.instance_eval %q{
p “using %q”
def b
puts “Ab::b”
end
}

boor.a
boor.b

==> “using block”
==> “using %q”
==> Ab::a
==> Ab::b

What have I missed ?

Thanks in advance.
Eli


#7

On Sat, May 13, 2006 at 05:28:19PM +0900, Eli B. wrote:

Is block eval the same as single-quoted-string eval ?

$ cat string.rb
def foo
instance_eval %{
387 8sbf fy"(/·%" /·/% "· ·· sdug sdf
}
end

puts “I can’t foresee any problem.”

much later, in code far, far away

#foo

$ ruby string.rb
I can’t foresee any problem.
$ cat block.rb
def foo
instance_eval do
387 8sbf fy"(/·%" /·/% "· ·· sdug sdf
end
end

puts “I can’t foresee any problem.”

much later, in code far, far away

#foo

$ ruby block.rb
block.rb:4: syntax error, unexpected tINTEGER, expecting kEND
387 8sbf fy"(/·%" /·/% "· ·· sdug sdf
^
block.rb:4: Invalid char \302' in expression block.rb:4: Invalid char\267’ in expression
block.rb:4: unterminated string meets end of file
block.rb:4: syntax error, unexpected tSTRING_END, expecting
tSTRING_CONTENT or tREGEXP_END or tSTRING_DBEG or tSTRING_DVAR

Another difference:

$ cat eval.rb
def foo_string(str)
eval str
instance_eval “var”
end

def foo_block(str)
eval str
instance_eval { var }
end

puts foo_string(“var = ‘some value’”)
puts foo_block(“var = ‘some value’”)

$ ruby eval.rb
some value
eval.rb:8:in foo_block': undefined local variable or methodvar’ for
main:Object (NameError)
from eval.rb:8:in `foo_block’
from eval.rb:12


#8

Mauricio F. wrote:

On Sat, May 13, 2006 at 05:28:19PM +0900, Eli B. wrote:

Is block eval the same as single-quoted-string eval ?

$ cat string.rb
def foo
instance_eval %{
387 8sbf fy"(/�%" /�/% "� �� sdug sdf
}
end

> > Another difference: > > $ cat eval.rb > def foo_string(str) > eval str > instance_eval "var" > end > > def foo_block(str) > eval str > instance_eval { var } > end > > > puts foo_string("var = 'some value'") > puts foo_block("var = 'some value'") >

OK, thanks - this I understand. The block version of eval checks the
block at compile time for errors, while the string version does not.
This is another plus for the block version, and generally I agree that
it should be used over the string version whenever that is possible.

The string version, however, has its uses, and can do things the block
version can’t, as I have shown in my examples. Such uses should be well
thought-out and kept to the minimum, of course.

Eli


#9

On Sat, 2006-05-13 at 14:52 +0900, Eli B. wrote:

The way I see it, the block version is simply a convenience, making the
code cleaner. It is similar to wrapping a string into a single
(non-interpolating) quote:

As well as the difference in when the code is parsed mentioned in
another post, it’s probably worth noting that string eval is slower than
block eval:

$ cat eval_bench2.rb
require ‘benchmark’
o = Object.new
Benchmark.bm(10) do |b|
b.report(“eval str:”) { 10000.times {o.instance_eval ‘10.times { |i| l
= 300 * i }’ }}
b.report(“eval blk:”) { 10000.times {o.instance_eval { 10.times { |i|
l = 300 * i }} }}
end

$ ruby -v eval_bench2.rb
ruby 1.8.4 (2005-12-24) [i686-linux]
user system total real
eval str: 0.340000 0.000000 0.340000 ( 0.416134)
eval blk: 0.160000 0.000000 0.160000 ( 0.203212)

In yarv, the difference is even more marked, and from what I can gather
it’s likely to stay that way:

$ ruby-yarv -v eval_bench2.rb
ruby 2.0.0 (Base: Ruby 1.9.0 2006-04-08) [i686-linux]
YARVCore 0.4.0 Rev: 497 (2006-05-07) [opts: ]
user system total real
eval str: 0.820000 0.020000 0.840000 ( 0.836336)
eval blk: 0.060000 0.000000 0.060000 ( 0.105170)


#10

ts wrote:

“E” == Eli B. removed_email_address@domain.invalid writes:

E> What have I missed ?

The evilness of eval.

Guy Decoux

Guy,

I would really appreciate a serious answer. The Ruby documentation is
bad, there’s no need to tell you that, and I’m trying to understand
things in depth, hence my questions.

I understand that eval can be mis-used, like many other advanced
features.

However, I much prefer a serious to-the-point answer. You have cleared
out a lot for me, and I thank you for that. What is left is my last
question:

Is block eval the same as single-quoted-string eval ?

Thanks in advance


#11

I genuinely have no clue what the difference is between class_eval and
instance_eval. Check out this quick irb session:

irb(main):111:0> class Foo; end
=> nil
irb(main):112:0> Foo.instance_eval { define_method(:foo) { “foo” } }
=> #Proc:0x00318b00@:112(irb)
irb(main):113:0> Foo.foo
NoMethodError: undefined method foo' for Foo:Class from (irb):113 from :0 irb(main):114:0> Foo.new.foo => "foo" irb(main):115:0> class Bar; end => nil irb(main):116:0> Bar.class_eval { define_method(:bar) { "bar" } } => #<Proc:0x003078a0@(irb):116> irb(main):117:0> Bar.bar NoMethodError: undefined methodbar’ for Bar:Class
from (irb):117
from :0
irb(main):118:0> Bar.new.bar
=> “bar”

I would think that since I used class_eval in one and instance_eval in
the other, SOMETHING should be different…

Pat


#12

Hi –

On Sun, 14 May 2006, Pat M. wrote:

  from :0

irb(main):118:0> Bar.new.bar
=> “bar”

I would think that since I used class_eval in one and instance_eval in
the other, SOMETHING should be different…

Fear not; it is :slight_smile: Look at what happens when you use def:

class C; end
=> nil

C.instance_eval { def x; 1; end } # singleton method on C
=> nil

C.x
=> 1

C.new.x
NoMethodError: undefined method `x’ for #<C:0x35b16c>
from (irb):4
from :0

C.class_eval { def y; 1; end } # instance method of C
=> nil

C.y
NoMethodError: undefined method `y’ for C:Class
from (irb):6
from :0

C.new.y
=> 1

C.instance_eval handles the business of C itself, as an object. You’d
get similar results with any_object.instance_eval { def x; 1; end }

C.class_eval takes you into a class definition block for C, where def
is an instance method of C. So it’s much more class (and module)
specific in its engineering.

David


#13

“P” == Pat M. removed_email_address@domain.invalid writes:

P> define_method: “Defines an instance method in the receiver…This
P> block is evaluated using instance_eval…”

Well, the block is not really evaluated with instance_eval

moulon% cat b.rb
#!/usr/bin/ruby
class A
def create_method(name, &block)
self.class.send(:define_method, name, &block)
end
end

class B
def a
A.new.create_method(:a) { def b() end }
end
end

B.new.a
A.new.a
A.new.b
moulon%

if the block ‘{ def b() end }’ is evaluated with instance_eval, ruby
will
create a singleton method, otherwise my script will work.

moulon% ./b.rb
moulon%

Guy Decoux


#14

On 5/14/06, removed_email_address@domain.invalid removed_email_address@domain.invalid wrote:

=> #Proc:0x00318b00@:112(irb)
irb(main):117:0> Bar.bar

C.class_eval { def y; 1; end } # instance method of C

Ruby and Rails consultancy and training

Okay so I guess the problem is that I’m using define_method? I don’t
understand the difference between define_method and def then.

define_method: “Defines an instance method in the receiver…This
block is evaluated using instance_eval…”

After first reading that, I thought it explained why there was no
difference between using instance_eval or class_eval with
define_method, because define_method uses instance_eval itself.
However isn’t self different when I use instance_eval vs class_eval,
so then the inner instance_eval call would operate on a different
self, making the results different?

Pat