Forum: Ruby Making sense of the various Ruby "eval"s

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Fc761ccaf6c0d7d977e2959f9bfebd06?d=identicon&s=25 Eli Bendersky (eliben)
on 2006-05-12 17:09
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
956f185be9eac1760a2a54e287c4c844?d=identicon&s=25 ts (Guest)
on 2006-05-12 17:33
(Received via mailing list)
>>>>> "E" == Eli Bendersky <eliben@gmail.com> writes:

E> - Kernel#eval -

 it's the evil eval, forget it :-)

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
Fc761ccaf6c0d7d977e2959f9bfebd06?d=identicon&s=25 Eli Bendersky (eliben)
on 2006-05-12 18:01
ts wrote:
>>>>>> "E" == Eli Bendersky <eliben@gmail.com> writes:
>
> E> - Kernel#eval -
>
>  it's the evil eval, forget it :-)

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
>
<snip>

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 ?
956f185be9eac1760a2a54e287c4c844?d=identicon&s=25 ts (Guest)
on 2006-05-12 18:11
(Received via mailing list)
>>>>> "E" == Eli Bendersky <eliben@gmail.com> writes:

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

 the string version is evil :-)

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
Fc761ccaf6c0d7d977e2959f9bfebd06?d=identicon&s=25 Eli Bendersky (eliben)
on 2006-05-13 07:52
ts wrote:
>>>>>> "E" == Eli Bendersky <eliben@gmail.com> writes:
>
> E> I'm struggling to fully understand the difference between the block
> and
> E> the string versions ?
>
>  the string version is evil :-)
>

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
956f185be9eac1760a2a54e287c4c844?d=identicon&s=25 ts (Guest)
on 2006-05-13 10:10
(Received via mailing list)
>>>>> "E" == Eli Bendersky <eliben@gmail.com> writes:

E> What have I missed ?

 The evilness of eval.

Guy Decoux
Fc761ccaf6c0d7d977e2959f9bfebd06?d=identicon&s=25 Eli Bendersky (eliben)
on 2006-05-13 10:28
ts wrote:
>>>>>> "E" == Eli Bendersky <eliben@gmail.com> 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
Dd76a12d66f843de5c5f8782668e7127?d=identicon&s=25 Mauricio Fernandez (Guest)
on 2006-05-13 11:05
(Received via mailing list)
On Sat, May 13, 2006 at 05:28:19PM +0900, Eli Bendersky 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 method `var' for
main:Object (NameError)
        from eval.rb:8:in `foo_block'
        from eval.rb:12
Fc761ccaf6c0d7d977e2959f9bfebd06?d=identicon&s=25 Eli Bendersky (eliben)
on 2006-05-13 11:27
Mauricio Fernandez wrote:
> On Sat, May 13, 2006 at 05:28:19PM +0900, Eli Bendersky wrote:
>>
>>
>> Is block eval the same as single-quoted-string eval ?
>
> $ cat string.rb
> def foo
>   instance_eval %{
>     387 8sbf fy"(/�%" /�/% "� �� sdug sdf
>   }
> end
>
<snip>
>
> 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'")
>
<snip>

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
A9b6a93b860020caf9d2d1d58c32478f?d=identicon&s=25 Ross Bamford (Guest)
on 2006-05-13 19:24
(Received via mailing list)
On Sat, 2006-05-13 at 14:52 +0900, Eli Bendersky 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)
42172acdf3c6046f84d644cb0b94642c?d=identicon&s=25 Pat Maddox (pergesu)
on 2006-05-14 08:44
(Received via mailing list)
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@(irb):112>
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 method `bar' 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
1fba4539b6cafe2e60a2916fa184fc2f?d=identicon&s=25 unknown (Guest)
on 2006-05-14 09:17
(Received via mailing list)
Hi --

On Sun, 14 May 2006, Pat Maddox 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 :-)  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
42172acdf3c6046f84d644cb0b94642c?d=identicon&s=25 Pat Maddox (pergesu)
on 2006-05-14 13:08
(Received via mailing list)
On 5/14/06, dblack@wobblini.net <dblack@wobblini.net> wrote:
> > => #<Proc:0x00318b00@(irb):112>
> > irb(main):117:0> Bar.bar
>
> >> C.class_eval { def y; 1; end } # instance method of C
>
>    > Ruby and Rails consultancy and training
> * Author of "Ruby for Rails" from Manning Publications!
>    > http://www.manning.com/black
>
>

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
956f185be9eac1760a2a54e287c4c844?d=identicon&s=25 ts (Guest)
on 2006-05-14 14:06
(Received via mailing list)
>>>>> "P" == Pat Maddox <pergesu@gmail.com> 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
This topic is locked and can not be replied to.