In article <9e3fd2c80602161324n4310a4ecx@mail.gmail.com>,
What I'm trying to do probably isn't possible, but maybe someone knows so=
me
deep magic.
I'd like something like:
def runit &b
a =3D 42
pnew =3D Proc.new &b, binding
pnew.call
end
runit { puts "a is: #{a}" }
#would print:
a is: 42
Or course, Proc.new currently doesn't take a Binding object second argume=
nt.
What I'm wondering is if there is any way to 'rebind' or 'recontextualize=
' a
block?
There is one way: you can use instance_eval with a block. This
essentially just rebinds self but this is good enough often.
Your example (even if the rebinding part worked) would likely suffer
from a different problem: a is not known as local variable in the
block so the compilation would probably not create code that reads the
local variable a.
Right, that's why instance_eval doesn't work for this case either.
Often there are alternative approaches, such as providing an argument
to the block that makes certain data accessible.
True. And that might be a possibility.
If you have a use
case in mind I'd be glad to try to come up with more suggestions.
Mainly I'm trying to make a DSL look prettier and reduce duplication.
The DSL is for simulating chip designs (RHDL).
I was going to have the user define a circuit, or logic gate, like so:
class AndGate < RHDL
inputs :a, :b
outputs :out
define_behavior { out << a & b }
end
And that particular gate definition would work, however given a different case:
class Counter < RHDL
inputs :clk, :rst
outputs :count_out
variables :count=>0
define_behavior {
process(clk) {
if clk.event and clk == 1
if rst == 1
count = 0
else
count += 1
end
count_out << count
end
}
}
end
Now we have a problem, but I'll have to explain a lot before I can get to
that...
The 'inputs' and 'outputs' methods create accessors for instance vars so that
in the define_behavior block with follows the user can refer to what will be
instance variables without needing to append '@' to them (they're accessed via
methods). It's an aesthetics issue: I didn't want the user to have to know
about instance vars and appanding '@'. It seems to work well.
However, notice the 'variables' method. The idea there is that there could be
some variables used in the define_behavior block (and this was the case with
the previous incarnation of RHDL, so I didn't want to lose that functionality).
Now by 'variable' here I mean that I want a variable that also has scope
within the define_behavior block. The define_behavior block will be called
many, many times during a simulation and I don't want the variable to be
re-initialzed on each call. It's a bit like:
def counter(init)
count = init
lambda { count += 1 }
end
count_val = counter(2)
count_val.call #=> 3
count_val.call #=> 4...
Ok, so now the issue is that the block being passed to define_method above
might need to refer to a 'variable' (from the variables list), but the problem
is that those variables don't exist yet when the block gets constructed or
evaluated (or whatever we call what happens when '{...}' is encountered).
I could make the user provide arguments to the block as you mentioned:
class Counter < RHDL
inputs :clk, :rst
outputs :count_out
variables :count=>0
define_behavior {|count|
#....
}
end
But they would be repeating themselves, no? 
So that's why I was trying to dynamically create a method that would have the
variables in the scope of the method and then the proc bound to that scope.
I suppose another way to do it would be to do:
class Counter < RHDL
inputs :clk, :rst
outputs :count_out
def initialize
count = 0
define_behavior {
#.... do something with count ...
}
end
end
This is sort of how RHDL is now. There's no need for a 'variables' method
since you just declare your variables in the 'initialize' method. I was trying
to get away from the explicit 'initialize' definition. But maybe it's not
such a bad thing. 'count' would then be available to the block passed to
define_behavior.
The other alternative is the one that Jim Freeze mentioned:
class Counter < RHDL
inputs :clk, :rst
outputs :count_out
variables :count=>0, :foo=>42
define_behavior %q{
#.... do something with count, foo ...
}
end
In that case defne_behavior takes a string instead of a block. That solves the
problem because the string can be evaluated later in different contexts.
But the '%q' is kind of ugly 
So it's a matter of tradeoffs... The other thing to keep in mind is that I want
to make it fairly easy to translate this DSL to another language (VHDL).
Having the explicit 'variables' declaration would probably make that easier
because it matches VHDL's semantics& syntax very closely.
Phil
···
Robert Klemme <shortcutter@googlemail.com> wrote:
2006/2/16, Phil Tomson <ptkwt@aracnet.com>: