Ruby proposal: MAIN_BINDING

What do you think about MAIN_BINDING for use it with eval():

    eval("a = 'hello'",MAIN_BINDING)
    puts a

outputs:
hello

?

Strictly speaking, there is no binding that would allow you to define new
variables in the main scope with the current semantics of #eval.

The issue (as I understand it), is that #eval opens up a new scope, sort of
like a block currently does, and variables don’t leak out of it. For example:

5.times do |i|
j = i
end

puts j

In Ruby 1.8 this fails because j isn’t defined (in Ruby 2.0, this won’t fail).

#eval is similar. It opens up a new scope that can only be accessed through
#eval, so you’d have to change the method itself. Strictly speaking, I guess
you could have a boolean argument that specifies whether #eval should use the
inner scope. That’d be more general.

Do I think it’s a good idea? I don’t know. :slight_smile: I recall reading threads here
where that kind of thing was necessary for what the person wanted to do (like
in your example. You can’t define new variables in the general scope). I don’t
really know how common it is, though. On the other hand, I don’t know how much
you need to protect the main scope.

Perhaps #eval should be changed to let variables leak out of eval-scope, just
like they’ll leak out of blocks in the future.

  • Dan
···

On Wednesday 21 April 2004 7:09 am, Szymon Drejewicz wrote:

What do you think about MAIN_BINDING for use it with eval():

    eval("a = 'hello'",MAIN_BINDING)
    puts a

outputs:
hello

Hi,

I’ve seen references to some TOP_LEVEL_BINDING in Google, I don’t know
if this is related.

I really feel strange about eval() not side effecting assignments
to new local variables. I guess the binding it uses is very special or
some logic is there to “undo” the creation of local variables. Weird.

For sure I don’t understand why this is happening in eval( stuff, binding).
If I provide a binding, I should have the option of whether is it rw or
rd_only.

But… I may be missing something.

Yours,

Jean-Hugues Robert

···

At 20:09 21/04/2004 +0900, you wrote:

What do you think about MAIN_BINDING for use it with eval():

    eval("a = 'hello'",MAIN_BINDING)
    puts a

outputs:
hello

?

Szymon Drejewicz drejewic@wsisiz.edu.pl writes:

What do you think about MAIN_BINDING for use it with eval():

    eval("a = 'hello'",MAIN_BINDING)
    puts a

outputs:
hello

?

Well, the following does work:

a = ‘goodbye’
eval(“a = ‘hello’”, binding())
puts a # => hello

The reason has to do with the differing manner in which ruby interprets
“puts a” in the presence and absence of a previous variable definition
for “a”.

If “a” is previously defined as a variable, the compiler causes the
“puts a” command to simply output its value; but if “a” is not
previously defined, my understanding is that “puts a” interprets “a” as
a method call. In this case, “eval” statement (whose command is not, of
course, touched by the interpreter) indeed sets the “a” variable in the
global scope, but the “print” statement doesn’t access it.

I’m don’t know if there’s a syntactical way around this.

···


Lloyd Zusman
ljz@asfast.com

The issue (as I understand it), is that #eval opens up a new scope

Well, not really. The problem is this is at *compile* time that ruby make
the difference between a variable and a method

When you write

      eval("a = 'hello'",MAIN_BINDING)
      puts a

ruby at compile time see a string and the statement

      puts a

which is interpreted as

      puts a() # method call because no local variable with the name `a'
               # was defined

and you can't change this, just imagine

     def tt(str)
        eval(str)
        puts a
     end

     tt("a = 'hello'")
     tt("b = 'hello'")

ruby will not be able to see, that *latter* the method #tt will be called
with "a = 'hello'", and in this case `a' can be a local variable.

Just imagine that ruby read line from a file and then call the method #tt
with these lines.

Worst and perhaps I've forgotten to say it : eval is evil

Guy Decoux

If “a” is previously defined as a variable, the compiler causes the
“puts a” command to simply output its value; but if “a” is not
previously defined, my understanding is that “puts a” interprets “a” as
a method call. In this case, “eval” statement (whose command is not, of
course, touched by the interpreter) indeed sets the “a” variable in the
global scope, but the “print” statement doesn’t access it.

I think you meant “local scope”?

I’m don’t know if there’s a syntactical way around this.

There are ways, but they aren’t beautiful.
for example:

eval(“a = 4”)
puts a = a
=> 4

By the asignment ruby will treat a as a local variable
and give the right result.

OK :slight_smile: eval is evil

You are right but if I can write

    eval("$name='Alice'")
    puts $name

and it’s OK, the same would be (hypothetically) with

    eval("name='Alice'", MAIN_BINDING)
    puts name

it just means “evaluate this command and execute it in main block…”

I know that is not so easy, but what’s wrong with that? Just want to write
self-writing code :slight_smile:

But… OK, Ruby is enough strong language even without my MAIN_BINDING :-]

    eval('proposal.reject')
···

Szymon Drejewicz

        eval("name='Alice'", MAIN_BINDING)
        puts name

Like have said matz the problem is with this

svg% cat b.rb
#!/usr/bin/ruby
def name
   "a nice method with a nice name"
end

eval("name='Alice'")
puts name
svg%

svg% b.rb
a nice method with a nice name
svg%

because at compile time, the local variable `name' was not defined ruby
has compiled the script to make a call to the method #name

it just means "evaluate this command and execute it in main block..."

yes, this is what do ruby but it do it at *runtime* when

    puts name

is interpreted at *compile* time.

This is at compile time, that ruby resolve `name' as

   *) reference to a local variable (if it was previously found a variable
      with this name)

   *) *OR* a method call (if it don't exist a variable with this name)

and in your example at *compile* time the variable `name' don't exist

I know that is not so easy, but what's wrong with that? Just want to write
self-writing code :slight_smile:

Don't make the error of a P language : an hash is really appropriate in
your case and it's perhaps the best solution

Guy Decoux