How to Marshal a Lambda (Proc) in Ruby

How do I marshal a lambda (Proc) in Ruby?

You cannot marshal a Lambda or Proc. This is because both of them are considered closures, which means they close around the memory on which they were defined and can reference it. (In order to marshal them you'd have to Marshal all of the memory they could access at the time they were created.)

As Gaius pointed out though, you can use ruby2ruby to get a hold of the string of the program. That is, you can marshal the string that represents the ruby code and then reevaluate it later.

How do you stringize/serialize Ruby code?

Use Ruby2Ruby

def save_for_later(&block)
return nil unless block_given?

c = Class.new
c.class_eval do
define_method :serializable, &block
end
s = Ruby2Ruby.translate(c, :serializable)
s.sub(/^def \S+\(([^\)]*)\)/, 'lambda { |\1|').sub(/end$/, '}')
end

x = 40
s = save_for_later { |y| x + y }
# => "lambda { |y|\n (x + y)\n}"
g = eval(s)
# => #<Proc:0x4037bb2c@(eval):1>
g.call(2)
# => 42

This is great, but it does not close over free variables (like x) and serialize them along with the lambda.

To serialize variables also, you can iterate over local_variables and serialize them as well. The problem, though, is that local_variables from within save_for_later accesses only c and s in the code above -- i.e. variables local to the serialization code, not the caller. So unfortunately, we must push the grabbing of local variables and their values to the caller.

Maybe this is a good thing, though, because in general, finding all free variables in a piece of Ruby code is undecidable. Plus, ideally we would also save global_variables and any loaded classes and their overridden methods. This seems impractical.

Using this simple approach, you get the following:

def save_for_later(local_vars, &block)
return nil unless block_given?

c = Class.new
c.class_eval do
define_method :serializable, &block
end
s = Ruby2Ruby.translate(c, :serializable)
locals = local_vars.map { |var,val| "#{var} = #{val.inspect}; " }.join
s.sub(/^def \S+\(([^\)]*)\)/, 'lambda { |\1| ' + locals).sub(/end$/, '}')
end

x = 40
s = save_for_later(local_variables.map{ |v| [v,eval(v)] }) { |y| x + y }
# => "lambda { |y| _ = 40; x = 40;\n (x + y)\n}"

# In a separate run of Ruby, where x is not defined...
g = eval("lambda { |y| _ = 40; x = 40;\n (x + y)\n}")
# => #<Proc:0xb7cfe9c0@(eval):1>
g.call(2)
# => 42

# Changing x does not affect it.
x = 7
g.call(3)
# => 43

How do I deep copy a Proc in Ruby?

Even if clone would work on Procs, it wouldn't help you, because you'd still be calling clone on the new value of @foo, not on the previous one like you want.

What you can do instead is just store the old value of @foo in a local variable that the lambda can close over.

Example:

def augment_foo()
old_foo = @foo
@foo = lambda { |x| x > 1 ? x*x : old_foo[x] }
end

This way old_foo will refer to the value that @foo had when augment_foo was called and everything will work as you want.

When to use lambda, when to use Proc.new?

Another important but subtle difference between procs created with lambda and procs created with Proc.new is how they handle the return statement:

  • In a lambda-created proc, the return statement returns only from the proc itself
  • In a Proc.new-created proc, the return statement is a little more surprising: it returns control not just from the proc, but also from the method enclosing the proc!

Here's lambda-created proc's return in action. It behaves in a way that you probably expect:

def whowouldwin

mylambda = lambda {return "Freddy"}
mylambda.call

# mylambda gets called and returns "Freddy", and execution
# continues on the next line

return "Jason"

end

whowouldwin
#=> "Jason"

Now here's a Proc.new-created proc's return doing the same thing. You're about to see one of those cases where Ruby breaks the much-vaunted Principle of Least Surprise:

def whowouldwin2

myproc = Proc.new {return "Freddy"}
myproc.call

# myproc gets called and returns "Freddy",
# but also returns control from whowhouldwin2!
# The line below *never* gets executed.

return "Jason"

end

whowouldwin2
#=> "Freddy"

Thanks to this surprising behavior (as well as less typing), I tend to favor using lambda over Proc.new when making procs.

Unable to use Proc/lambda returned from method in select/reject filters in Ruby

You need to remove the colon:

list.select(&valid_transaction)

The & syntax is used to pass a lambda or proc to a method that is expecting a block. That's what you need here.

With a colon, the effect is somewhat different:

list.select(&:valid_transaction)

is equivalent to this:

list.select { |tx| tx.valid_transaction }

Which is not what you intend at all.

The reason the colon has this affect is that Ruby calls #to_proc on the & argument. A symbol (which is what :valid_transaction is) responds to #to_proc by creating a proc that calls the method named by the symbol.

Change the binding of a Proc in Ruby

You can try the following hack:

class Proc
def call_with_vars(vars, *args)
Struct.new(*vars.keys).new(*vars.values).instance_exec(*args, &self)
end
end

To be used like this:

irb(main):001:0* lambda { foo }.call_with_vars(:foo => 3)
=> 3
irb(main):002:0> lambda { |a| foo + a }.call_with_vars({:foo => 3}, 1)
=> 4

This is not a very general solution, though. It would be better if we could give it Binding instance instead of a Hash and do the following:

l = lambda { |a| foo + a }
foo = 3
l.call_with_binding(binding, 1) # => 4

Using the following, more complex hack, this exact behaviour can be achieved:

class LookupStack
def initialize(bindings = [])
@bindings = bindings
end

def method_missing(m, *args)
@bindings.reverse_each do |bind|
begin
method = eval("method(%s)" % m.inspect, bind)
rescue NameError
else
return method.call(*args)
end
begin
value = eval(m.to_s, bind)
return value
rescue NameError
end
end
raise NoMethodError
end

def push_binding(bind)
@bindings.push bind
end

def push_instance(obj)
@bindings.push obj.instance_eval { binding }
end

def push_hash(vars)
push_instance Struct.new(*vars.keys).new(*vars.values)
end

def run_proc(p, *args)
instance_exec(*args, &p)
end
end

class Proc
def call_with_binding(bind, *args)
LookupStack.new([bind]).run_proc(self, *args)
end
end

Basically we define ourselves a manual name lookup stack and instance_exec our proc against it. This is a very flexible mechanism. It not only enables the implementation of call_with_binding, it can also be used to build up much more complex lookup chains:

l = lambda { |a| local + func(2) + some_method(1) + var + a }

local = 1
def func(x) x end

class Foo < Struct.new(:add)
def some_method(x) x + add end
end

stack = LookupStack.new
stack.push_binding(binding)
stack.push_instance(Foo.new(2))
stack.push_hash(:var => 4)

p stack.run_proc(l, 5)

This prints 15, as expected :)

UPDATE: Code is now also available at Github. I use this for one my projects too now.

Ruby: marshal and unmarshal a variable, not an instance

There's ObjectSpace._id2ref :

f = Foo.new #=> #<Foo:0x10036c9b8> 
f.object_id #=> 2149278940
ObjectSpace._id2ref(2149278940) #=> #<Foo:0x10036c9b8>

In addition to the caveats about garbage collection ObjectSpace carries a large performance penalty in jruby (so much so that it's disabled by default)

Is it possible to see the ruby code in a proc?

Take a look at the sourcify gem:

proc { x + y }.to_source
# >> "proc { (x + y) }"


Related Topics



Leave a reply



Submit