I Know Nothing

Ro 2009

This is a page about Execution and Custom Control Structures.

I found out that I know nothing about how execution happens, how the tcltk interpreter works, and what it's capable of. In the end, I truly know nothing.

  proc imdone {} {
    puts "yknow what, im done"
    set level [info level]
    return -level $level -code return
  }

When you execute this, at any time, from any proc, however many levels deep: all execution ends. No error, it just triggers a cascading normal return.

To people who understand everything already (har har), this is nothing new. But to me, it just about rendered me incapable of thought and threw into questioning everything I knew about life.

I'm used to thinking that g2 will return, and g1 will continue running. But no, when you use return with the -level option, you can actually cause the interpreter to finish all execution.

  proc g2 {} {
    puts G2-hello
    imdone
    puts G2-goodbye
  }

  proc g1 {} {
    puts g1-BEGIN
    g2
    puts g1-END
  }

  g1

So that's the first bit of code.


The magic really comes from 8.5's return and catch and tip 90 . Tip 90 specified new options for those two commands, which allows us to capture more information from the interp's execution (using catch), and pass more information to it (using return).

Now when you do custom control structures you may want to make your new fancy structure be transparent, which really means it doesn't show up in the stack trace when bad things happen (uncaught exceptions). I'm not going to bother with that, because I find it adds a lot of code where you're manipulating the printable stack trace (the -errorinfo value of the options dict). It's fine with me if you see the innards of our custom control structures inside a stack trace. After all, they are pure tcl procs, so why not?

It really helps if you think of codes being passed by callframes (procs) as exceptions. Exceptions unwind the stack, and codes are the same, they keep travelling up procs until the -level hits zero.


proc limited_while {cond body {limit 10}} {
  set n 0
  while 1 {
    if {$n == $limit} {
      error "hit limit of $n loops"
    }

    # evaluate the condition
    #
    set c [uplevel [list catch [list expr $cond] ::m ::o]]

    # if the evaluation doesnt return ok, then throw exception
    #
    if {$c != 0} {
      dict incr ::o -level
      return -options $::o $::m
    }

    # now the condition actually evaluated but is it true?
    #
    if {$::m != 1} {
      return
    }

    # ok so now we evaluate the body
    #
    set c [uplevel [list catch $body ::m ::o]]

    # ok 0              next iteration
    # error 1 return 2  throw exception
    # break 3           quit this proc
    # continue 4        next iteration just like ok 0
    #
    switch -exact -- $c {
      0 {}
      3 {
        return
      }
      4 {}
      default {
        dict incr ::o -level
        return -options $::o $::m
      }      
    }

    incr n
  }
  return
}

  set i 0
  limited_while {$i < 5} {

    if {$i == 3} {break}
    puts $i

    incr i
  }

AMG: "I Know Nothing" is also the title of a track on the GameChops album "The TRIFORCE of BASS". Listen here: [L1 ].