Ticket Change Details
Not logged in
Overview

Artifact ID: 6454bd5ca8f25248798ddbf805b35461f51841da
Ticket: bfe0f34e6ca558c525d3d649f93970e2267b5ff1
catch and yieldto
User & Date: sebres 2017-06-06 16:41:47
Changes

  1. closedate changed to: "2457911.19569003"
  2. closer changed to: "sebres"
  3. 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).
    
  4. login: "sebres"
  5. mimetype: "text/x-fossil-wiki"