Why is the Binding object so useless?

I am used to Ruby being a rather reflective language that gives carte
blanche to the programmer. So I found this rather surprising:

Marshal.dump binding
TypeError: no marshal_dump is defined for class Binding

Whaa?

Binding.new
NoMethodError: undefined method `new’ for Binding:Class

Huh?

binding.methods(false)
=> []

You’re kidding me, right?

I would expect you to be able to do all of the above. In addition to
that,
it’s sure be nice to do some of the following:

Binding.new :a => 1, :b => 2, :c =>3
=> #Binding:0x1018130b0 # new binding object with the given variables
bound

binding.to_hash
=> {:a => 1, :b => 2, :c => 3} # Bound variables, as a hash

binding.to_yaml
=> “— !ruby/object:Binding \na: 1\nb: 2\nc: 3\n” # YAML dump of a
Binding
object

And hey, maybe Binding#inspect could give a little more information than
its
object_id?

Canned responses to apologists:

= Why do you want to do that?

I don’t know, why should you be able to redefine Integer#+?

= No really, why do you want to do that?

I would like to implement a remote REPL with a stateless Ruby server and
a
non-Ruby client

= Just use DRb!

I am really not wanting to open up an addition port just for DRb nor
pursue
solutions which involve a non-Ruby client talking the DRb protocol.
Embedding some form of Ruby interpreter client side is not an option.

Props to Rubinius for fixing some of these problems!

irb(main):001:0> Binding.new
=> #Binding:0x2e0

Yay! A clean binding!

Marshal.dump Binding.new
=> “\004\bo:\fBinding\000”

Amazing!

Tony A. wrote:

= No really, why do you want to do that?

I would like to implement a remote REPL with a stateless Ruby server and
a
non-Ruby client

Your proposed feature would also make things like the ActionPack
template rendering much cleaner. grep for “local_assigns” in
action_view/renderable.rb (rails 2.3.x) and weep. Here is what they end
up doing, where local_assigns is a hash of variable=>value bindings:

  def compile!(render_symbol, local_assigns)
    locals_code = local_assigns.keys.map { |key| "#{key} = 

local_assigns[:#{key}];" }.join

    source = <<-end_src
      def #{render_symbol}(local_assigns)
        old_output_buffer = 

output_buffer;#{locals_code};#{compiled_source}
ensure
self.output_buffer = old_output_buffer
end
end_src

(Rails 3 is the same, but the file is action_view/template.rb and the
method is compile not compile!)

The above is probably what your REPL server should do.

I guess what you propose wasn’t implemented simply because it involves
work to convert bindings between their internal representation and
external forms like Hash and Marshal#dump. If you grab an existing live
binding and pass it around, the conversion isn’t required.

2010/1/25 Tony A. [email protected]:

I am used to Ruby being a rather reflective language that gives carte
blanche to the programmer. So I found this rather surprising:

Marshal.dump binding
TypeError: no marshal_dump is defined for class Binding

Whaa?

I don’t think it does make sense to serialize a binding for the same
reason that you cannot create a new binding: a binding is bound to a
particular program context - I assume this also includes caller stack
and other internal state.

Even if a binding contains local variables what is the effect of
deserializing a binding? If your local variables get updated that is
certainly not a good idea. If you want to serialize state use objects
with the proper state.

Binding.new
NoMethodError: undefined method `new’ for Binding:Class

Huh?

A binding is not a regular object but it is a handle on the state of
the runtime. A method object cannot be serialized as well because
that would mean that the original code would have to be written (and
read); this also has security implications (in the case of Method).

But if you have to_hash you can serialize that.

I would expect you to be able to do all of the above. In addition to that,
it’s sure be nice to do some of the following:

Binding.new :a => 1, :b => 2, :c =>3
=> #Binding:0x1018130b0 # new binding object with the given variables
bound

As above.

binding.to_hash
=> {:a => 1, :b => 2, :c => 3} # Bound variables, as a hash
binding.to_yaml
=> “— !ruby/object:Binding \na: 1\nb: 2\nc: 3\n” # YAML dump of a Binding
object

Same as above for Marshal.

And hey, maybe Binding#inspect could give a little more information than its
object_id?

Yeah, #to_hash and #inspect sound pretty good. You might even add a
method #update receiving a Hash which is interpreted as a mapping from
local variables to values and which overwrites the current binding.

Kind regards

robert

On Tue, Jan 26, 2010 at 8:07 AM, Robert K.
[email protected]wrote:

reason that you cannot create a new binding: a binding is bound to a
particular program context - I assume this also includes caller stack
and other internal state.

Why can’t bindings be independently garbage collected objects too? (as
it
appears they are in rbx)

Even if a binding contains local variables what is the effect of
deserializing a binding? If your local variables get updated that is
certainly not a good idea. If you want to serialize state use objects
with the proper state.

The goal is to have an object to pass to eval as the binding argument,
not
to update locals.

Ideally I could pass a fresh binding (made with Binding.new) to eval,
and
when eval is finished it will be updated with whatever assignments were
made
in the evaluated code. I could then serialize this and persist it until
the
next eval call.