An example of implementing [iterators] using [Closures]. This is just an experiment!!! -- [Todd Coram] The code below (using code from [Closures]) allows us to create a ''forward'' iterator command in pure Tcl that works with strings, lists, channels and ''ranges'' of numbers. This way we can write truly "generic" functions in Tcl that operate on the above without knowledge of type. Scroll to the bottom for examples. make-closure-proc iterator {_type _target} { variable type $_type variable target {$_target} variable pos -1 variable end -1 } { variable type; switch -glob -- $type { -str* { set end [string length $target] set nextbody { incr pos if {$pos >= $end} { return {} } return [string index $target $pos] } } -li* { set end [llength $target] set nextbody { incr pos if {$pos >= $end} { return {} } return [lindex $target $pos] } } -chan* { set end {} set nextbody { if {[eof $target]} { return {} } return [gets $target] } } -rang* { set end [lindex $target 1] set pos [expr {[lindex $target 0] - 1}] set nextbody { if {$pos >= $end} { return {} } return [incr pos] } } default { error "iterator: bad option \"$type\": must be -string, -list, -channel or -range" } } # if you use the lambda hack (from [Closures]): # lambda {} "variable target; variable pos; variable end; $nextbody" # otherwise the below 2 lines will work too.. proc next {} "variable target; variable pos; variable end; $nextbody" return [namespace current]::next } Here are a few examples: set i1 [iterator -string "hello world"] set i2 [iterator -list {hello world}] set i3 [iterator -channel [open somefile.txt r]] set i4 [iterator -range {1 100}] proc count {iter} { set count 0 while {[$iter] != {}} { incr count } return $count } count $i1 ;# returns 11 count $i2 ;# returns 2 count $i3 ;# returns the number of characters in the file. count $i4 ;# returns 100 We can now define a couple of ''useful'' generic functions: proc iforeach {var iter body} { while {[set $var [$iter]] != {}} { eval $body } } proc map {iter cmd} { set res {} while {[set v [$iter]] != {}} { lappend res [eval $cmd $v] } return $res } Which can be used as follows: iforeach x [iterator -string "hi mom!"] { puts "Got $x" } iforeach x [iterator -range {12 24}] { puts "$x" } proc double {x} {expr {$x * 2}} map [iterator -range {0 10}] double map [iterator -list {1 2 3 4 5}] double map [iterator -chan stdin] double ;# double every number entered on the console (1 per line) map [iterator -string "12345"] double ;# this doesn't do what you may expect ;-) The map proc looks better using lambda: map [iterator -range {0 10}] [lambda x {expr {$x * 2}}] Note that while ''iforeach'' doesn't properly emulate ''foreach''(different scoping of variables), you could use it as a replacement for ''foreach'' on plain old lists: iforeach x [iterator -list [array names env]] { puts $x } is the effectively the same as foreach x [array names env] { puts $x } except in the latter, x has a value in the calling scope. Since iterator objects respond to ''info command'', you could always write a super-foreach that accepts iterators ''and'' plain lists... Here is a rewrite of map that works with iterators or lists: proc map {iter_or_list cmd} { set res {} if {[info command $iter_or_list] == {}} { foreach v $iter_or_list { lappend res [eval $cmd $v] } } else { while {[set v [$iter_or_list]] != {}} { lappend res [eval $cmd $v] } } return $res } map {1 2 3 4} double map [iterator -range {1 4}] double -----