Hashes and Blocks (Syntactical/Feature question)

Discussion in 'Ruby' started by Pete Elmore, Oct 30, 2004.

  1. Pete Elmore

    Pete Elmore Guest

    -----BEGIN PGP SIGNED MESSAGE-----
    Hash: SHA1

    I haven't been able to find any documentation on the syntax for a
    certain feature, and am not sure the feature exists. What I would like
    to do is add a block of code to a hash, so I could do something like this:

    state = 0
    states = {
    0 => { puts "State 0"; state = 1 },
    1 => { puts "State 1"; state = 0 }
    }

    However, I haven't found any documentation on doing anything like this,
    so I'm not sure you can. What I'm doing right now is a little ugly:

    state = 0
    states = {
    0 => "puts 'State 0'; state = 1",
    1 => "puts 'State 1'; state = 0"
    }

    while a_condition
    eval states[state]
    end

    Obviously, keeping code as a string and then using eval gets pretty
    hairy if it gets any more complicated than this. The ability to pass
    blocks as data is one of Ruby's best features, and this would allow
    programmers to avoid constructs like
    state = X
    data.each { |datum|
    if state == 0
    code
    elsif state == 1
    other code
    ...
    }

    (If this is repugnant to the nature of Ruby, there's a better way to do
    it, or it already exists and I've missed it, please forgive my n00b
    question!)
    -----BEGIN PGP SIGNATURE-----
    Version: GnuPG v1.2.5 (GNU/Linux)
    Comment: Using GnuPG with Debian - http://enigmail.mozdev.org

    iD8DBQFBgu+Yv24lB609Ih8RAvYhAKCSYQyZcpT/nj6LJJCBlxKHhkceUACfVca5
    hrLw6eGQwZ7XZh2B2an/toc=
    =uKEd
    -----END PGP SIGNATURE-----
    Pete Elmore, Oct 30, 2004
    #1
    1. Advertising

  2. Pete Elmore wrote:
    > -----BEGIN PGP SIGNED MESSAGE-----
    > Hash: SHA1
    >
    > I haven't been able to find any documentation on the syntax for a
    > certain feature, and am not sure the feature exists. What I would like
    > to do is add a block of code to a hash, so I could do something like this:
    >
    > state = 0
    > states = {
    > 0 => { puts "State 0"; state = 1 },
    > 1 => { puts "State 1"; state = 0 }
    > }


    state = 0
    states = {
    0 => Proc.new { puts "State 0"; state = 1 },
    1 => Proc.new { puts "State 1"; state = 0 }
    }

    while a_condition
    states[state].call
    end
    Andreas Schwarz, Oct 30, 2004
    #2
    1. Advertising

  3. On Saturday, October 30, 2004, 11:29:20 AM, Pete wrote:

    > I haven't been able to find any documentation on the syntax for a
    > certain feature, and am not sure the feature exists. What I would like
    > to do is add a block of code to a hash, so I could do something like this:


    > state = 0
    > states = {
    > 0 => { puts "State 0"; state = 1 },
    > 1 => { puts "State 1"; state = 0 }
    > }


    It's pretty easy:

    state = 0
    states = {
    0 => lambda { puts "State 0"; state = 1 },
    ...
    }

    while a_condition
    states[state].call
    end

    Cheers,
    Gavin
    Gavin Sinclair, Oct 30, 2004
    #3
  4. "Gavin Sinclair" <> schrieb im Newsbeitrag
    news:...
    > On Saturday, October 30, 2004, 11:29:20 AM, Pete wrote:
    >
    >> I haven't been able to find any documentation on the syntax for a
    >> certain feature, and am not sure the feature exists. What I would like
    >> to do is add a block of code to a hash, so I could do something like
    >> this:

    >
    >> state = 0
    >> states = {
    >> 0 => { puts "State 0"; state = 1 },
    >> 1 => { puts "State 1"; state = 0 }
    >> }

    >
    > It's pretty easy:
    >
    > state = 0
    > states = {
    > 0 => lambda { puts "State 0"; state = 1 },
    > ...
    > }
    >
    > while a_condition
    > states[state].call
    > end


    And you can even define default behavior:

    state = 0
    states = Hash.new( lambda { puts "fallback" } ).update(
    0 => lambda { puts "State 0"; state = 1 },
    1 => lambda { puts "State 1"; state = 0 }
    )

    loop do
    states[rand 100].call
    end

    or even (for individual fallbacks)

    states = Hash.new { |h,k| h[k] = lambda { puts "fallback for #{k}" } }
    ..update(
    0 => lambda { puts "State 0"; state = 1 },
    1 => lambda { puts "State 1"; state = 0 }
    )

    >> 10.times {|i| states.call }

    State 0
    State 1
    fallback for 2
    fallback for 3
    fallback for 4
    fallback for 5
    fallback for 6
    fallback for 7
    fallback for 8
    fallback for 9
    => 10

    Kind regards

    robert
    Robert Klemme, Oct 30, 2004
    #4
  5. Pete Elmore

    Jim Haungs Guest

    What's a hashtable with names pointing to code blocks?
    Hmm... Sounds like a class!

    What you're trying to do is an example of the State pattern, which is
    often implemented with sensibly-named states (as opposed to the
    numbers in the example here). The state names are really method names;
    you perform the operation for some state X by sending the X message to
    an instance of the State class. The class can also encapsulate the
    current state of the machine, track state transitions, or whatever.

    And if you need multiple instances of the state machine, you just
    create a new instance of the State class.

    With the hash table scheme, the cohesion is poor because the current
    machine state is separated from the operations on that state.

    On Sat, 30 Oct 2004 14:31:19 +0200, "Robert Klemme" <>
    wrote:

    >
    >"Gavin Sinclair" <> schrieb im Newsbeitrag
    >news:...
    >> On Saturday, October 30, 2004, 11:29:20 AM, Pete wrote:
    >>
    >>> I haven't been able to find any documentation on the syntax for a
    >>> certain feature, and am not sure the feature exists. What I would like
    >>> to do is add a block of code to a hash, so I could do something like
    >>> this:

    >>
    >>> state = 0
    >>> states = {
    >>> 0 => { puts "State 0"; state = 1 },
    >>> 1 => { puts "State 1"; state = 0 }
    >>> }

    >>
    >> It's pretty easy:
    >>
    >> state = 0
    >> states = {
    >> 0 => lambda { puts "State 0"; state = 1 },
    >> ...
    >> }
    >>
    >> while a_condition
    >> states[state].call
    >> end

    >
    >And you can even define default behavior:
    >
    >state = 0
    >states = Hash.new( lambda { puts "fallback" } ).update(
    > 0 => lambda { puts "State 0"; state = 1 },
    > 1 => lambda { puts "State 1"; state = 0 }
    >)
    >
    >loop do
    > states[rand 100].call
    >end
    >
    >or even (for individual fallbacks)
    >
    >states = Hash.new { |h,k| h[k] = lambda { puts "fallback for #{k}" } }
    >.update(
    > 0 => lambda { puts "State 0"; state = 1 },
    > 1 => lambda { puts "State 1"; state = 0 }
    >)
    >
    >>> 10.times {|i| states.call }

    >State 0
    >State 1
    >fallback for 2
    >fallback for 3
    >fallback for 4
    >fallback for 5
    >fallback for 6
    >fallback for 7
    >fallback for 8
    >fallback for 9
    >=> 10
    >
    >Kind regards
    >
    > robert
    >
    Jim Haungs, Nov 4, 2004
    #5
  6. "Jim Haungs" <> schrieb im Newsbeitrag
    news:...
    > What's a hashtable with names pointing to code blocks?
    > Hmm... Sounds like a class!


    Yeah, you can view it that way.

    > What you're trying to do is an example of the State pattern, which is
    > often implemented with sensibly-named states (as opposed to the
    > numbers in the example here). The state names are really method names;


    I beg to differ at this point: state names are usually translated to class
    names. Events are translated to methods (see the example below).

    > you perform the operation for some state X by sending the X message to
    > an instance of the State class.


    Again, I'd rephrase that to "you perform some operation Y for state X by
    sending the message Y to an instance of X.

    > The class can also encapsulate the
    > current state of the machine, track state transitions, or whatever.


    State transitions are tracked by exchanging the instance.

    > And if you need multiple instances of the state machine, you just
    > create a new instance of the State class.


    Yep.

    > With the hash table scheme, the cohesion is poor because the current
    > machine state is separated from the operations on that state.


    That's true although it's what the OP asked for. :)

    Kind regards

    robert


    Example

    class Window
    def initialize
    @state = WinClose.new
    end

    # actions
    def look() @state.look end

    # queries
    def open?() @state.open? end

    # transitions
    def open() @state = @state.open end
    def close() @state = @state.close end

    private
    class WinOpen
    # actions
    def look() "beautiful landscape" end

    # queries
    def open?() true end

    # transitions
    def open() raise "You can't open an open window" end
    def close() WinClose.new end
    end

    class WinClose
    # actions
    def look() nil end

    # queries
    def open?() false end

    # transitions
    def open() WinOpen.new end
    def close() raise "You can't close a closed window" end
    end
    end


    > On Sat, 30 Oct 2004 14:31:19 +0200, "Robert Klemme" <>
    > wrote:
    >
    > >
    > >"Gavin Sinclair" <> schrieb im Newsbeitrag
    > >news:...
    > >> On Saturday, October 30, 2004, 11:29:20 AM, Pete wrote:
    > >>
    > >>> I haven't been able to find any documentation on the syntax for a
    > >>> certain feature, and am not sure the feature exists. What I would

    like
    > >>> to do is add a block of code to a hash, so I could do something like
    > >>> this:
    > >>
    > >>> state = 0
    > >>> states = {
    > >>> 0 => { puts "State 0"; state = 1 },
    > >>> 1 => { puts "State 1"; state = 0 }
    > >>> }
    > >>
    > >> It's pretty easy:
    > >>
    > >> state = 0
    > >> states = {
    > >> 0 => lambda { puts "State 0"; state = 1 },
    > >> ...
    > >> }
    > >>
    > >> while a_condition
    > >> states[state].call
    > >> end

    > >
    > >And you can even define default behavior:
    > >
    > >state = 0
    > >states = Hash.new( lambda { puts "fallback" } ).update(
    > > 0 => lambda { puts "State 0"; state = 1 },
    > > 1 => lambda { puts "State 1"; state = 0 }
    > >)
    > >
    > >loop do
    > > states[rand 100].call
    > >end
    > >
    > >or even (for individual fallbacks)
    > >
    > >states = Hash.new { |h,k| h[k] = lambda { puts "fallback for #{k}" } }
    > >.update(
    > > 0 => lambda { puts "State 0"; state = 1 },
    > > 1 => lambda { puts "State 1"; state = 0 }
    > >)
    > >
    > >>> 10.times {|i| states.call }

    > >State 0
    > >State 1
    > >fallback for 2
    > >fallback for 3
    > >fallback for 4
    > >fallback for 5
    > >fallback for 6
    > >fallback for 7
    > >fallback for 8
    > >fallback for 9
    > >=> 10
    > >
    > >Kind regards
    > >
    > > robert
    > >

    >
    Robert Klemme, Nov 4, 2004
    #6
  7. Pete Elmore

    Pete Elmore Guest

    -----BEGIN PGP SIGNED MESSAGE-----
    Hash: SHA1

    Thanks for all of the helpful responses!

    "Gavin Sinclair" <> wrote:
    | states = Hash.new( lambda { puts "fallback" } ).update(
    That's interesting; it had not occurred to me to use the default hash
    value like that.

    "Jim Haungs" <> wrote:
    | What you're trying to do is an example of the State pattern, which is
    | often implemented with sensibly-named states (as opposed to the
    | numbers in the example here).
    Yeah, actually, I was simplifying it a little; I used names for the states.
    | With the hash table scheme, the cohesion is poor because the current
    | machine state is separated from the operations on that state.
    Very good point. But writing a class to handle a state machine for a
    program that was about thirty lines could have made it quite a bit
    longer/more complicated. ;)

    The program actually generated Ruby code that was used by another Ruby
    program to perform the tedious task of writing assembly language for the
    PIC microcontroller (whew).
    -----BEGIN PGP SIGNATURE-----
    Version: GnuPG v1.2.5 (GNU/Linux)
    Comment: Using GnuPG with Debian - http://enigmail.mozdev.org

    iD8DBQFBigJTv24lB609Ih8RAtbdAJsHdHSY7pik1xWT8bYSGkef7sIpqgCfV2JQ
    QN9AALBzXPT1Puc6DbIx+Sw=
    =KcEB
    -----END PGP SIGNATURE-----
    Pete Elmore, Nov 4, 2004
    #7
    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. Olumide
    Replies:
    10
    Views:
    628
    Richard Herring
    Sep 17, 2007
  2. matt
    Replies:
    1
    Views:
    254
    George Ogata
    Aug 6, 2004
  3. djacober

    Question about hashes of hashes

    djacober, Jul 24, 2005, in forum: Perl Misc
    Replies:
    10
    Views:
    182
    Ian Wilson
    Jul 25, 2005
  4. Tim O'Donovan

    Hash of hashes, of hashes, of arrays of hashes

    Tim O'Donovan, Oct 27, 2005, in forum: Perl Misc
    Replies:
    5
    Views:
    208
  5. Replies:
    3
    Views:
    205
Loading...

Share This Page