Proc question

Hello,

Let’s say that I have created a proc like:

a = proc{ puts x } (NOT! a = proc{ |x| puts x })

In this case, x within the scope of the proc does not exist and proc ‘a’
is
unable to receive an argument to set it…

If I wanted to take proc ‘a’ and create another proc, which did include
arguments…

In fact, lets say I just wanted to grab an existing proc, modify the
parameters to include |*args|, knowing that within the existing proc, I
am
grabbing my passed variables from the args array, even though they, at
that
point, don’t exist…

I did find the ‘parameters’ method on Proc and I found that when a proc
has
arity of 0, parameters is an empty array, and then depending on the
argument, parameters will return something like [ [:opt, :x], [:opt, :y]
]
for |x, y| or [ [:rest, :args] ] for |*args|…

However, parameters, while it certain LOOKS like it is taking the values
if
I pass (<<) the appropriate values to it, they will not actually store.

I also played around a little bit with grabbing the binding of the proc
without parameters and then trying to create the required variables
within
that binding, but I didn’t try too hard which is probably why it didn’t
work, because in theory, that should be doable.

Is what I am attempting to do possible? Or is there a work-around that
isn’t too hacky?

Thanks in advance,

Daniel

irb(main):003:0> a.parameters.object_id
=> 70140113536380

Oh duh… I think the 108 degree heat was affecting me today :slight_smile: I did
actually, more aptly, try using send :instance_variable_set, [[:req,
:x],
[:req, :y]] without avail too…

I think someone more knowledgeable than I would have to explain exactly
why Binding#local_variable_set isn’t designed to solve problems such as
this (I’m sure there’s either a good technical, difficulty of
implementation or even language design reason). However, I do know it’s not
just that you’re doing it wrong, it just doesn’t support that behavior:

Class: Binding (Ruby 2.1.2)

From the example code in the doc for that method, you can see that even
though Binding#local_variable_set works to set a variable in a binding,
actual code in the same scope that tries to reference said local variable
still raises a NameError.

While not particularly elegant, I did find a workable solution using
instance_exec or instance_exec and binding.

a, b, c = 1, 2, 3
instance_exec(&proc{ puts a, b, c }) #=> 1\n2\n3\n
However, wrapped within some sort of container like a module or method
so
we don’t have to worry about variable collisions.

Or bareword-esque within a single binding
b = binding
b.define_singleton_method(:myvar){ 3 }
b.instance_exec(&proc{ puts myvar })

Definitely a good place to start!

Thanks!

On Wed, Jul 2, 2014 at 8:18 AM, Daniel M. [email protected]
wrote:

arguments…

However, parameters, while it certain LOOKS like it is taking the values
if I pass (<<) the appropriate values to it, they will not actually store.

The array instance returned by #parameters is just for your information.
Mutating it has not effect because clearly, you’re just getting a new
array
instance each time you call #parameters (likely generated from internal
state you don’t have direct access to):

irb(main):001:0> a = proc { puts x }
=> #Proc:0x007f95891baca8@:1(irb)
irb(main):002:0> a.parameters.object_id
=> 70140113542620
irb(main):003:0> a.parameters.object_id
=> 70140113536380

There is not way that I’m aware of to posthumously mutate a Proc. At
best,
you can #curry the proc to get a new proc, but that’s not a mutation of
the
original proc, just a way to “wrap” it.

I also played around a little bit with grabbing the binding of the proc
without parameters and then trying to create the required variables within
that binding, but I didn’t try too hard which is probably why it didn’t
work, because in theory, that should be doable.

Yeah, with the new #local_variable_set and #local_variable_get, it does
seem like it’d work to a.local_variable_set(:x, “hello world”) but as
you
figured out, it doesn’t, even though a.local_variable_get(:x) will
indicate
the set did in fact work.

Is what I am attempting to do possible? Or is there a work-around that
isn’t too hacky?

I think someone more knowledgeable than I would have to explain exactly
why
Binding#local_variable_set isn’t designed to solve problems such as this
(I’m sure there’s either a good technical, difficulty of implementation
or
even language design reason). However, I do know it’s not just that
you’re
doing it wrong, it just doesn’t support that behavior:

From the example code in the doc for that method, you can see that even
though Binding#local_variable_set works to set a variable in a
binding,
actual code in the same scope that tries to reference said local
variable
still raises a NameError.

On Wed, Jul 2, 2014 at 4:18 PM, Daniel M. [email protected]
wrote:

In fact, lets say I just wanted to grab an existing proc, modify the
parameters to include |*args|, knowing that within the existing proc, I am
grabbing my passed variables from the args array, even though they, at that
point, don’t exist…

Is what I am attempting to do possible? Or is there a work-around that isn’t
too hacky?

Frankly, I did not even fully understand what you are attempting to
do. I mean, technically yes. And there is no way I can think of that
would work. But why do you think you need that and what problem do
you want to solve with this?

Kind regards

robert