[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Hashes and Blocks (Syntactical/Feature question

Pete Elmore

10/30/2004 1:29:00 AM

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

iD8DBQFBgu+Yv24lB609Ih8RAvYhAKCSYQyZcpT/nj6LJJCBlxKHhkceUACfVca5
hrLw6eGQwZ7XZh2B2an/toc=
=uKEd
-----END PGP SIGNATURE-----


6 Answers

Andreas Schwarz

10/30/2004 1:35:00 AM

0

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

Gavin Sinclair

10/30/2004 1:37:00 AM

0

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



Robert Klemme

10/30/2004 12:31:00 PM

0


"Gavin Sinclair" <gsinclair@soyabean.com.au> schrieb im Newsbeitrag
news:193-2098986814.20041030113810@soyabean.com.au...
> 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[i].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

11/4/2004 3:29:00 AM

0

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" <bob.news@gmx.net>
wrote:

>
>"Gavin Sinclair" <gsinclair@soyabean.com.au> schrieb im Newsbeitrag
>news:193-2098986814.20041030113810@soyabean.com.au...
>> 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[i].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

11/4/2004 9:47:00 AM

0


"Jim Haungs" <jhaungs@acm.org> schrieb im Newsbeitrag
news:1s7jo05tnlpljnvdaim5ptiig8tbjitvsn@4ax.com...
> 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" <bob.news@gmx.net>
> wrote:
>
> >
> >"Gavin Sinclair" <gsinclair@soyabean.com.au> schrieb im Newsbeitrag
> >news:193-2098986814.20041030113810@soyabean.com.au...
> >> 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[i].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
> >
>

Pete Elmore

11/4/2004 10:14:00 AM

0

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

Thanks for all of the helpful responses!

"Gavin Sinclair" <gsinclair@soyabean.com.au> 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" <jhaungs@acm.org> 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....

iD8DBQFBigJTv24lB609Ih8RAtbdAJsHdHSY7pik1xWT8bYSGkef7sIpqgCfV2JQ
QN9AALBzXPT1Puc6DbIx+Sw=
=KcEB
-----END PGP SIGNATURE-----