Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Ruby > recontextualizing a block (looking for deep magic)

Reply
Thread Tools

recontextualizing a block (looking for deep magic)

 
 
Phil Tomson
Guest
Posts: n/a
 
      02-16-2006
What I'm trying to do probably isn't possible, but maybe someone knows some
deep magic.

I'd like something like:

def runit &b
a = 42
pnew = 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 argument.
What I'm wondering is if there is any way to 'rebind' or 'recontextualize' a
block?


Phil
 
Reply With Quote
 
 
 
 
Robert Klemme
Guest
Posts: n/a
 
      02-16-2006
2006/2/16, Phil Tomson <(E-Mail Removed)>:
> 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.

Often there are alternative approaches, such as providing an argument
to the block that makes certain data accessible. If you have a use
case in mind I'd be glad to try to come up with more suggestions.

Kind regards

robert

--
Have a look: http://www.flickr.com/photos/fussel-foto/


 
Reply With Quote
 
 
 
 
Jim Freeze
Guest
Posts: n/a
 
      02-16-2006
On 2/16/06, Phil Tomson <(E-Mail Removed)> wrote:
> 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?


This is interesting. For a while you had me thinking the Proc.new {} should
rebind, but I couldn't get it to. Seems that the binding is based upon wher=
e the
block is defined inside the file.

This is the closest I could get:

def runit(b)
a =3D 42
pnew =3D lambda { eval(b,binding) }
pnew.call
end

runit %q{ puts "a is: #{a}" }



--
Jim Freeze


 
Reply With Quote
 
Phil Tomson
Guest
Posts: n/a
 
      02-16-2006
In article <5cd596d60602161330o67494818oadaad45229662f5c@mail .gmail.com>,
Jim Freeze <(E-Mail Removed)> wrote:
>On 2/16/06, Phil Tomson <(E-Mail Removed)> wrote:
>> 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?

>
>This is interesting. For a while you had me thinking the Proc.new {} should
>rebind, but I couldn't get it to. Seems that the binding is based upon wher=
>e the
>block is defined inside the file.


Right. And 99% of the time that's what you want because they're closures.
.... but sometimes I find I want the block evaluation to be delayed and done in
a different binding.

I think a Proc.new that took a binding would be useful sometimes, but I'm not
hopeful that it could be implemented without mucking around with Ruby's
internals (in C).

>
>This is the closest I could get:
>
> def runit(b)
> a =3D 42
> pnew =3D lambda { eval(b,binding) }
> pnew.call
> end
>
> runit %q{ puts "a is: #{a}" }
>


Yeah, I eventually came up with pretty-much the same thing. This is probably
what I'll end up doing since:
%q{ ... }

doesn't look all that different from the regular block syntax:
{ ... }

....but as this is for a DSL, I'm sure users are going to be thinking "what the
heck is the %q for?" and I don't blame them. It hurts the aesthetics.

Phil
 
Reply With Quote
 
Phil Tomson
Guest
Posts: n/a
 
      02-16-2006
In article <(E-Mail Removed)>,
Robert Klemme <(E-Mail Removed)> wrote:
>2006/2/16, Phil Tomson <(E-Mail Removed)>:
>> 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 ut

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
 
Reply With Quote
 
Jacob Fugal
Guest
Posts: n/a
 
      02-16-2006
(Responding to myself...)

On 2/16/06, Jacob Fugal <(E-Mail Removed)> wrote:
> Why not something like this then?
>
> class Counter < RHDL
> inputs :clk, :rst
> outputs :count_out
>
> count =3D 0
> define_behavior {
> #.... do something with count ...
> }
> end


I just realized that what define_behavior (on the class) probably does
is store the block which will then be passed to define_behavior (on
the instance) during the default initialize. Each instance has its own
copy of the block and should have it's own state in count. The code I
posted above won't work like that; all instances would share the same
count, obviously not what you wanted. So... nevermind.

Jacob Fugal


 
Reply With Quote
 
Glen
Guest
Posts: n/a
 
      02-17-2006
Phil Tomson wrote:
> I'd like something like:
>
> def runit &b
> a = 42
> pnew = Proc.new &b, binding
> pnew.call
> end
>
> runit { puts "a is: #{a}" }
>
> #would print:
> a is: 42



Hi, I am not sure I understood your question, and since noone else has
suggested this yet, I assume that it is not what you are looking for.
But I will post it anyway. Does this do what you want?

def runit &b
a = 42
pnew = Proc.new(&b)
pnew.call(a)
end

runit { |a| puts "a is: #{a}" }

--
Glen

 
Reply With Quote
 
Robert Klemme
Guest
Posts: n/a
 
      02-17-2006
Phil Tomson wrote:
> In article <(E-Mail Removed)>,
> Robert Klemme <(E-Mail Removed)> wrote:
>> 2006/2/16, Phil Tomson <(E-Mail Removed)>:
>>> 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 ut
>
> 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?


And especially assigning to "count" would be useless.

How ugly do you feel about

define_behavior {|in,out,var|
if in[:rst]
var[:count]=0
elsif in[:clk]
var[:count]+=1
end
}

This has the added benefits of

- giving you the choice what to provide as arguments (could be simply
hashes but anything else that supports the interface)

- introducing separate namespaces for each type of variable

But then again, using plain instance variables might be even simpler and
less cluterrish...

> 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.


IMHO explicit is not bad. Often it makes code more readable and
maintainable.

> 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


Yes.

> 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.


Kind regards

robert

 
Reply With Quote
 
Pit Capitain
Guest
Posts: n/a
 
      02-17-2006
Phil Tomson schrieb:
> ...
>
> 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
>
> ...
>
> 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.
>
> ...


Phil, I don't understand the usage of variables. When should they be
initialized? What should be their scope (class, instance, thread,
other)? Can't you use instance variables with accessor methods?

Regards,
Pit



 
Reply With Quote
 
Phil Tomson
Guest
Posts: n/a
 
      02-17-2006
In article <(E-Mail Removed)>,
Robert Klemme <(E-Mail Removed)> wrote:
>Phil Tomson wrote:
>
>How ugly do you feel about
>
>define_behavior {|in,out,var|
> if in[:rst]
> var[:count]=0
> elsif in[:clk]
> var[:count]+=1
> end
>}


I'd rather just go ahead and use the '@'.

>
>This has the added benefits of
>
> - giving you the choice what to provide as arguments (could be simply
>hashes but anything else that supports the interface)
>
> - introducing separate namespaces for each type of variable
>
>But then again, using plain instance variables might be even simpler and
>less cluterrish...
>
>> 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.

>
>IMHO explicit is not bad. Often it makes code more readable and
>maintainable.


True, but.... but since this is a DSL it seems to add a bit of clutter. With
the other 'syntax' shown earlier, the 'initialize' method is generated
automatically so that it takes the inputs and outputs:

ag = AndGate.new(a,b,result)

that seems kind of nice...

>
>> 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

>
>Yes.


....but it could be the least of the evils.

Phil
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
recontextualizing art sobriquet Digital Photography 1 03-11-2012 04:52 PM
Fo:Block can you check to see if a block contains any text by using the block id? morrell XML 1 10-10-2006 07:18 PM
Deep Freeze In Deep Trouble johntangelo@gmail.com Computer Security 3 10-25-2005 11:49 PM
Problem with enterprise application block - data block Showjumper ASP .Net 1 03-19-2005 03:48 PM



Advertisments