Version 2 of namespace unknown

Updated 2006-11-13 19:27:53

A new feature in Tcl 8.5 that extends the unknown mechanism to be customisable on a per-namespace basis. See TIP 181 for details [L1 ].


NEM 13 Nov 2006: Here is an updated version of let unknown know that makes use of 8.5 features: namespace unknown and apply. While (much) longer than the original version, each "known" snippet can have its own parameters, with all the usual forms accepted by proc (i.e., defaults, args). Wrapping of new functionality is essentially completely transparent, and each new known thing executes as an independent proc, without adding new command names. You can delegate to the next unknown handler by calling next (or returning a continue exception). Without arguments, next will invoke the next handler with the original command line, otherwise it will pass the rewritten form.

 proc know {params body} {
    set ns [uplevel 1 { namespace current }]
    set old [namespace eval $ns { namespace unknown }]
    set new [list $params $body $ns]
    namespace eval $ns [list namespace unknown [list ::known $new $old]]
 }
 proc known {handler old args} {
    set rc [catch { uplevel 1 [linsert $args 0 ::apply $handler] } result]
    if {$rc == 4} {
        # continue - invoke next handler
        if {[llength $result] == 0} {
            uplevel 1 $old $args
        } else {
            uplevel 1 $old $result
        }
    } else {
        return -code $rc $result
    }
 }
 proc next args { return -code continue -level 2 $args }

Examples of use:

 # expand leading word
 know {cmd args} {
   if {[llength $cmd] > 1} { uplevel 1 $cmd $args } else { next }
 }
 # numeric ranges
 proc range {from to} {
     set ret [list]
     while {$from <= $to} { lappend ret $from; incr from }
     return $ret
 }
 know {args} { 
   if {[regexp {^([0-9]+)\.\.([0-9]+)$} $args -> from to]} {
     range $from $to
   } else { next }
 }

DGP It appears that next here is just continue by a different name. Why not just use continue, or if the next name is a must have, then why not have it as an alias?

 interp alias {} next {} continue

[ Category Command ]