recontextualizing a block (looking for deep magic)

Discussion in 'Ruby' started by Phil Tomson, Feb 16, 2006.

  1. Phil Tomson

    Phil Tomson Guest

    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
    Phil Tomson, Feb 16, 2006
    #1
    1. Advertising

  2. 2006/2/16, Phil Tomson <>:
    > 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/
    Robert Klemme, Feb 16, 2006
    #2
    1. Advertising

  3. Phil Tomson

    Jim Freeze Guest

    On 2/16/06, Phil Tomson <> 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
    Jim Freeze, Feb 16, 2006
    #3
  4. Phil Tomson

    Phil Tomson Guest

    In article <>,
    Jim Freeze <> wrote:
    >On 2/16/06, Phil Tomson <> 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
    Phil Tomson, Feb 16, 2006
    #4
  5. Phil Tomson

    Phil Tomson Guest

    In article <>,
    Robert Klemme <> wrote:
    >2006/2/16, Phil Tomson <>:
    >> 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 :eek: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
    Phil Tomson, Feb 16, 2006
    #5
  6. Phil Tomson

    Jacob Fugal Guest

    (Responding to myself...)

    On 2/16/06, Jacob Fugal <> 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
    Jacob Fugal, Feb 16, 2006
    #6
  7. Phil Tomson

    Glen Guest

    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
    Glen, Feb 17, 2006
    #7
  8. Phil Tomson wrote:
    > In article <>,
    > Robert Klemme <> wrote:
    >> 2006/2/16, Phil Tomson <>:
    >>> 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 :eek: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
    Robert Klemme, Feb 17, 2006
    #8
  9. Phil Tomson

    Pit Capitain Guest

    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
    Pit Capitain, Feb 17, 2006
    #9
  10. Phil Tomson

    Phil Tomson Guest

    In article <>,
    Robert Klemme <> 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
    Phil Tomson, Feb 17, 2006
    #10
  11. Phil Tomson

    Phil Tomson Guest

    In article <>,
    Pit Capitain <> wrote:
    >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?
    >


    Well, it's a bit strange in the example above. Really what I want is for it to
    be method-level, I suppose. Recall that I showed an alternative where the user
    actually defines the initialize method explicitly:



    #....
    def initialize
    count = 0
    define_behvior {
    #...do something with count ...
    }
    end


    In that scenario count is a variable whose scope is within the initialize
    method. It can also be referred to within the scope of the block passed to
    define_behavior (define_behavior in that case just assigns the block to a
    @behavior instance variable.)


    In the scenario of the code snippet you quote above the idea was to somehow
    have the behavior block 'recontextualized' within the context of a generated
    method:
    def get_behavior
    count = 0
    #define_behavior block stored in @behavior:
    #the following line is not real Ruby:
    recontextualized_proc = Proc.new &@behavior, binding
    end

    then later on the proc can be called.

    Of course, if we pass a string to define_behavior and store it, then we can use
    the way shown by Jim Freeze to acheive the same thing. The count variable then
    gets initialized to a value outside of the behavior block and is available
    within the behavior block.

    Phil
    Phil Tomson, Feb 17, 2006
    #11
  12. Phil Tomson

    Pit Capitain Guest

    Phil Tomson schrieb:
    > Well, it's a bit strange in the example above. Really what I want is for it to
    > be method-level, I suppose. Recall that I showed an alternative where the user
    > actually defines the initialize method explicitly:
    >
    > #....
    > def initialize
    > count = 0
    > define_behvior {
    > #...do something with count ...
    > }
    > end


    Hi Phil, sorry for the late reply. I had to implement part of the code
    to understand why you can't use accessor methods for variables. Accessor
    methods for inputs and outputs are no problem because you just read from
    the inputs and set the outputs with a method call (<<). The problem with
    variables is that you want to be able to set them via assignment, and
    for Ruby

    variable = value

    never is a method call. You could write

    self.variable = value

    or use other methods to set the value of a variable, but with assignment
    you have to use local variables, like you've shown in the explicit
    initialize method above.

    Regards,
    Pit
    Pit Capitain, Feb 21, 2006
    #12
  13. Phil Tomson

    Phil Tomson Guest

    In article <>,
    Pit Capitain <> wrote:
    >Phil Tomson schrieb:
    >> Well, it's a bit strange in the example above. Really what I want is for it to
    >> be method-level, I suppose. Recall that I showed an alternative where the user
    >> actually defines the initialize method explicitly:
    >>
    >> #....
    >> def initialize
    >> count = 0
    >> define_behvior {
    >> #...do something with count ...
    >> }
    >> end

    >
    >Hi Phil, sorry for the late reply. I had to implement part of the code
    >to understand why you can't use accessor methods for variables. Accessor
    >methods for inputs and outputs are no problem because you just read from
    >the inputs and set the outputs with a method call (<<). The problem with
    >variables is that you want to be able to set them via assignment, and
    >for Ruby
    >
    > variable = value
    >
    >never is a method call. You could write
    >
    > self.variable = value
    >
    >or use other methods to set the value of a variable, but with assignment
    > you have to use local variables, like you've shown in the explicit
    >initialize method above.
    >


    Right. Here's what I finally came up with:

    class AndGate < RHDL
    inputs :a, :b
    outputs :eek:ut
    init {
    somevar = 0
    define_behavior {
    out << (a & b)
    puts "somevar is: #{somevar}"
    somevar +=1
    }
    }
    end

    So the 'init' method allows a place to 'declare' variables which will also be
    available to the define_behavior block. The advantage of this over the
    explicit initialize is that there is no repetition of information (you'd have
    to pass the inputs and outputs to the initialize method) as I generate the
    initialize method so that given the above description, the AndGate could be
    used as:

    sa = Sig.new(Bit(0))
    sb = Sig.new(Bit(0))
    sout= Sig.new(Bit())

    a = AndGate.new(sa,sb,sout) #initialize was automatically generated

    also, the 'init' block is optional. If you have no variables to initialize
    then you don't need it:

    class AndGate < RHDL
    inputs :a, :b
    outputs :eek:ut
    define_behavior {
    out << (a & b)
    }
    end

    BTW: I'm thinking of using '<=' for assignment instead of '<<' since '<=' has
    lower precedence than '<<' and that would allow:
    out <= a & b #parens not required

    I still wish we had a ':=' operator that could be defined that would have the
    same precedense as '='.

    Phil
    Phil Tomson, Feb 23, 2006
    #13
  14. Phil Tomson

    Pit Capitain Guest

    Phil Tomson schrieb:
    >
    > Here's what I finally came up with:
    >
    > class AndGate < RHDL
    > inputs :a, :b
    > outputs :eek:ut
    > init {
    > somevar = 0
    > define_behavior {
    > out << (a & b)
    > puts "somevar is: #{somevar}"
    > somevar +=1
    > }
    > }
    > end


    This is a nice looking compromise.

    > BTW: I'm thinking of using '<=' for assignment instead of '<<' since '<=' has
    > lower precedence than '<<' and that would allow:
    > out <= a & b #parens not required


    I think you know this already, but if you would use the same assignment
    operator for variables, you could omit the init method.

    Regards,
    Pit
    Pit Capitain, Feb 25, 2006
    #14
  15. Phil Tomson

    Phil Tomson Guest

    In article <>,
    Pit Capitain <> wrote:
    >Phil Tomson schrieb:
    >>
    >> Here's what I finally came up with:
    >>
    >> class AndGate < RHDL
    >> inputs :a, :b
    >> outputs :eek:ut
    >> init {
    >> somevar = 0
    >> define_behavior {
    >> out << (a & b)
    >> puts "somevar is: #{somevar}"
    >> somevar +=1
    >> }
    >> }
    >> end

    >
    >This is a nice looking compromise.
    >
    >> BTW: I'm thinking of using '<=' for assignment instead of '<<' since '<=' has
    >> lower precedence than '<<' and that would allow:
    >> out <= a & b #parens not required

    >
    >I think you know this already, but if you would use the same assignment
    >operator for variables, you could omit the init method.
    >


    Right. I've considered that option, but for now I think it's better to make
    the distinction between variables and signals (other HDLs make the distinction
    as well where variables are considered to change 'immediately' while signals
    change at the end of the block evaluation).

    The other change I'm considering is hiding the explicit class
    definition, like so:

    AndGate = Circuit {
    inputs :a, :b
    outputs :eek:ut
    init {
    somevar = 0
    define_behavior {
    out <= a & b
    puts "somevar is: #{somevar}"
    somevar +=1
    }
    }
    }
    g=AndGate.new(a,b,a_and_b)

    Where Circuit is defined something like:

    def Circuit &b
    #...
    klass=Class.new(RHDL) &b
    #...
    klass
    end

    That would hide a little more 'Rubyness' behind the DSL curtain.

    Phil
    Phil Tomson, Feb 25, 2006
    #15
  16. Phil Tomson

    Pit Capitain Guest

    Phil Tomson schrieb:
    >
    > The other change I'm considering is hiding the explicit class
    > definition, like so:
    > ...
    > That would hide a little more 'Rubyness' behind the DSL curtain.


    If you want to hide even more of Ruby you could try to get rid of symbols:

    class RHDL
    class << self
    def method_missing(name, *) name end
    def inputs(*args) p [:inputs, *args] end
    def outputs(*args) p [:eek:utputs, *args] end
    end
    end

    Class.new RHDL do
    inputs a, b
    outputs out
    end

    # => [:inputs, :a, :b]
    # => [:eek:utputs, :eek:ut]

    In reality you'd have to do more than shown here, but I think it could work.

    Regards,
    Pit
    Pit Capitain, Feb 25, 2006
    #16
  17. Phil Tomson

    Phil Tomson Guest

    In article <>,
    Pit Capitain <> wrote:
    >Phil Tomson schrieb:
    >>
    >> The other change I'm considering is hiding the explicit class
    >> definition, like so:
    >> ...
    >> That would hide a little more 'Rubyness' behind the DSL curtain.

    >
    >If you want to hide even more of Ruby you could try to get rid of symbols:
    >
    > class RHDL
    > class << self
    > def method_missing(name, *) name end
    > def inputs(*args) p [:inputs, *args] end
    > def outputs(*args) p [:eek:utputs, *args] end
    > end
    > end
    >
    > Class.new RHDL do
    > inputs a, b
    > outputs out
    > end
    >
    > # => [:inputs, :a, :b]
    > # => [:eek:utputs, :eek:ut]
    >
    >In reality you'd have to do more than shown here, but I think it could work.
    >


    Oh, I like that! I think I'll give it a try.

    Phil
    Phil Tomson, Feb 25, 2006
    #17
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Showjumper
    Replies:
    1
    Views:
    688
    Showjumper
    Mar 19, 2005
  2. Jan Burgy
    Replies:
    2
    Views:
    590
    Jan Burgy
    Aug 16, 2004
  3. Bengt Richter
    Replies:
    3
    Views:
    314
    Mike Meyer
    Nov 23, 2005
  4. morrell
    Replies:
    1
    Views:
    933
    roy axenov
    Oct 10, 2006
  5. Giles Bowkett
    Replies:
    9
    Views:
    394
    Giles Bowkett
    Dec 17, 2007
Loading...

Share This Page