CMcC 2009-02-28: You can call a coroutine as a method of an object. You can create a coroutine in a method of an object, and later invoke the coro as if it were a method of the object. The coro can access object variables and invoke methods of the object from the coro.
package require TclOO
namespace import oo::*
class create coro_oo {
variable var ;# can be referenced from the coro by ::variable
method meth {v} {puts $v} ;# can be called by the coro by [my meth]
method start {} {
coroutine moop ::apply [list args {
variable var ;# this variable is the object's variable
while {1} {
set args [yield $var]
my meth $var ;# call a method from the coro
}
} [self]]
objdefine [self] forward moop [self]::moop ;# forward the method to the coro
}
constructor {} {
set var "this var (v) can be seen from the coro via 'variable' command"
}
}
set x [coro_oo new] ;# create the test object
$x start ;# call start to generate the coro
puts [$x moop "calling via forward"]Similar methodology would permit you to use proc instead of apply (because you can create a proc within a method of an object, too, and use that as the functional content of your coro), but apply is so cool.
DKF: Here's a variation on this theme, a class (designed for subclassing) that intermingles itself with a coroutine, which I wrote for the subtasks of this page (where I'm using it to do arithmetic over infinite continued fractions):
oo::class create Generator {
constructor {} {
coroutine [namespace current]::coro my Apply
}
destructor {
catch {rename [namespace current]::coro {}}
}
method Apply {} {
yield
my Produce
my destroy
return -code break
}
forward generate coro
method unknown args {
if {![llength $args]} {
tailcall coro
}
next {*}$args
}
method collect {} {
set result {}
while 1 {
lappend result [my generate]
}
return $result
}
method take {n {suffix ""}} {
set result {}
for {set i 0} {$i < $n} {incr i} {
lappend result [my generate]
}
while {$suffix ne ""} {
my generate
lappend result $suffix
break
}
return $result
}
}Example use:
oo::class create SpitOutOnes {
superclass Generator
method Produce {} {
while true {
yield 1
}
}
}
set seq [SpitOutOnes new]
puts [join [$seq take 20 "\u2026"] ","]Which produces this output
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,…