Overview
| Artifact ID: | 6454bd5ca8f25248798ddbf805b35461f51841da |
|---|---|
| Ticket: | bfe0f34e6ca558c525d3d649f93970e2267b5ff1
catch and yieldto |
| User & Date: | sebres 2017-06-06 16:41:47 |
Changes
- closedate changed to: "2457911.19569003"
- closer changed to: "sebres"
- icomment:
> Somebody with the NRE "in his cache" might give some insight here. > For this reason, an error in a coroutine "pops up" back to the closest [coroutine] or resumption The coroutine is scope-less execution with anchoring on the execution level (without possibility to upvar/uplevel etc). Sometimes it is just good to imagine "how coroutines work", to take a look on example like this: <code><pre> % proc out {args} {::puts {*}[lrange $args 0 end-1] [string repeat " " [expr {[info level]-1}]][lindex $args end]} % % out 0:[info level]; apply {{} { out 1:[info level]; apply {{} { out 2:[info level] }} }} 0:0 1:1 2:2 % out 0:[info level]; coroutine c1 apply {{} { out 1:[info level]; coroutine c2 apply {{} { out 2:[info level] }} }} 0:0 1:1 2:1 </pre></code> Another example is good to explain "yieldto": <code><pre> % proc out {args} { set lev [set rlev [expr {[info level]-1}]] if {[regexp {^::\D*(\d+)} [info coroutine] _ lev]} {incr lev $rlev} ::puts {*}[lrange $args 0 end-1] [string repeat " " $lev][lindex $args end] } % % proc test {c1body c2body} { out "++ test enter"; if {[catch { coroutine c1 ::apply [list [list [list c1body $c1body] [list c2body $c2body]] { out "++ c1 enter" coroutine c2 ::apply [list [list [list c2body $c2body]] { out "++ c2 enter" yield out "** c2" if 1 $c2body out "-- c2 leave" }] out "** c1" if {[catch $c1body r]} { out "** c1 !! ERROR: $r" } out "-- c1 leave" }] } errMsg]} { out "** test !! ERROR: $errMsg"; } out "** test" if {[namespace which -command c1] ne ""} { out "** test .. continue ::c1" c1; # finish c1 if expected } out "-- test leave"; } % % test {yieldto c2} {out "** c2 .. BOOM"; error "BOOM"} ++ test enter ++ c1 enter ++ c2 enter ** c1 ** c2 ** c2 .. BOOM ** test !! ERROR: BOOM ** test ** test .. continue ::c1 -- c1 leave -- test leave % test {yieldto c2} {out "** c2 .. OK"; return OK} ++ test enter ++ c1 enter ++ c2 enter ** c1 ** c2 ** c2 .. OK ** test ** test .. continue ::c1 -- c1 leave -- test leave % test {yieldto c2} {out "** c2 .. back to c1"; yieldto c1} ++ test enter ++ c1 enter ++ c2 enter ** c1 ** c2 ** c2 .. back to c1 -- c1 leave ** test -- test leave % % test {c2} {out "** c2 .. BOOM"; error "BOOM"} ++ test enter ++ c1 enter ++ c2 enter ** c1 ** c2 ** c2 .. BOOM ** c1 !! ERROR: BOOM -- c1 leave ** test -- test leave % test {c2} {out "** c2 .. OK"; return OK} ++ test enter ++ c1 enter ++ c2 enter ** c1 ** c2 ** c2 .. OK -- c1 leave ** test -- test leave % test {c2} {out "** c2 .. back to c1"; yieldto c1} ++ test enter ++ c1 enter ++ c2 enter ** c1 ** c2 ** c2 .. back to c1 ** c1 !! ERROR: coroutine "c1" is already running -- c1 leave ** test -- test leave % </pre></code> Note that the correct way to use "yieldto" explained above in 3th example: <code><pre> test {yieldto c2} {out "** c2 .. back to c1"; yieldto c1} </pre></code> My conclusion also: the subject is indeed not a bug (as you already correct said).<br/> But IMHO the logic of "yieldto" can be extended a bit. I'll try to specify my idea resp. to describe or explain what I want to do later (too many things are currently open). - login: "sebres"
- mimetype: "text/x-fossil-wiki"