'''the serial incrementor''' I stumbled across a sweet way to create an autoincrementing variable for use in loops and such. It allows me to write code like: ====== % source serial.tcl % serial create s % foreach fruit {apples oranges pears banannas} { > puts [format {%03d %s} $s $fruit] >} 001 apples 002 oranges 003 pears 004 banannas ====== Anyway, I'm so impressed by my own cleverness, that I need to post it online immediately. (It needs [SubCommands and named arguments] to work... ------------------------- ====== #serial.tcl #Copyright April 13, 2005 - Pierre Coueffin source subcommands.tcl proc serial {command args} { subcommand $command args { create {var {start 1} {step 1}} { incr start [expr -1 * $step] upvar $var v if {[regexp {read {serial trace (-?[0-9]+)}} \ [trace info variable v]]} { error "The variable $var has already been declared serial." } set v $start trace add variable v read [list serial trace $step] } array {var vals {step 1}} { upvar $var v foreach {idx val} $vals { set v($idx) [expr $val - $step] } trace add variable v read [list serial trace $step] } trace {step var idx _op} { upvar $var v if {$idx == {}} { incr v $step } else { incr v($idx) $step } } forget {var} { upvar $var v trace remove variable v read \ [list serial trace [serial stepsize v]] } stepsize {var {newstep {}}} { upvar $var v if {[llength $newstep] > 0} { serial forget v serial create v $v $newstep return $v } else { regexp {read {serial trace (-?[0-9]+)}} \ [trace info variable v] match step return $step } } last {var} { upvar $var v return [incr v [expr -1 * [serial stepsize v]]] } default {} { error "serial: I don't know how to \"$command\"!" } } } ====== -------- [SS] With [Jim Closures] it's as simple as: ====== proc make-counter {} {lambda {} {{i 0}} {incr i}} set s [make-counter] foreach fruit {apples oranges pears banannas} { puts [format {%s %s} [$s] $fruit] } ====== output: 1 apples 2 oranges 3 pears 4 banannas -------------------- [Pierre Coueffin]: Wow, you're fast! I had a few other samples to post, but you managed to slip the edit in while I was checking that the last one worked... I'll just tuck them away here: ====== % puts $s 5 % puts $s 6 % serial last s 7 % serial last s 7 % serial stepsize s 1 % serial stepsize s 10 7 % puts $s 17 % set s 5 5 % puts $s 15 % puts $s 25 % puts $s 35 ====== Or how about an array of them? ====== % serial array sa {0 0 1 5 bob 3} 2 % puts $sa(0) 0 % puts $sa(0) 2 % puts $sa(0) 4 % % puts $sa(bob) 3 % puts $sa(bob) 5 % puts $sa(bob) 7 ====== ---- [escargo] 2005-04-13: This very much like [Icon Programming Language%|%Icon] generators, which produce a new value when they are invoked. (Icon generators cannot have their current value and step size increased like these can.) ---- [RS] has this variation: ====== set s 0 trace add variable s read {incr s ;#} foreach fruit {apples oranges pears bananas} { puts [format {%s %s} $s $fruit] } ====== which shows ======none 1 apples 2 oranges 3 pears 4 banannas ====== ---- [rdt] Wow, leave it to [RS] to come up with a simple, easy to use solution. Thanks. <> Dev. Tools | Command