[Richard Suchenwirth] - To extend Tcl, i.e. to make it understand and do things that before raised an error, the easiest way is to write a [proc]. Any proc must however be called in compliance with Tcl's fundamental syntax: first word is the command name, then the arguments separated by whitespace. Deeper changes are possible with the [unknown] command, which is called if a command name is, well, unknown, and in the standard version tries to call executables, to auto-load scripts, or do other helpful things (see the file init.tcl). One could edit that file (not recommended), or rename ''unknown'' to something else and provide one's own unknown handler, that falls through to the original proc if unsuccessful, as shown in [Radical language modification]. Here is a simpler way that allows to extend [unknown] "in place" and incrementally: We let [unknown] "know" what action it shall take under what conditions. The ''know'' command is called with a '''condition''' that should result in an integer when given to [expr], and a '''body''' that will be executed if ''cond'' results in nonzero, returning the last result if not terminated with an explicit [return]. In both ''cond'' and ''body'' you may use the variable ''args'' that holds the problem command ''unknown'' was invoked with. proc know {cond body} { proc unknown {args} [string map [list @c@ $cond @b@ $body] { if {![catch {expr {@c@}} res] && $res} { return [eval {@b@}] } }][info body unknown] } if 0 {''Condition'' and ''body'' are wrapped together and prepended to the previous [unknown] body. This means that subsequent calls to ''know'' stack up, last condition being tried first, so if you have several conditions that fire on the same input, let them be "known" from generic to specific. Here's a little debugging helper, if "know" conditions don't fire: } proc know? {} {puts [string range [info body unknown] 0 511]} if 0 {Now testing what new magic this handful of code allows us to do. This simple example invokes [expr] if the "command" is digestible for it: know {[expr $args] || 1} {expr $args} % 1+2 * 3 7 The "||(or) 1" appended in the condition lets this fire even if the expression would result in zero... I started these experiments because I wanted to have an infix index vector constructor (cf. [Playing Haskell]), so [[1..4]] returns {1 2 3 4}: know {[regexp {^([0-9]+)\.\.([0-9]+)$} [lindex $args 0] -> from to]} { set res {} while {$from<=$to} {lappend res $from; incr from} set res } % puts [1..5] 1 2 3 4 5 Here's a weird experiment with a "reverse Polish" command (see [RPN in Tcl]): % know {[lindex $args end]=="say"} {puts [lrange $args 0 end-1]} % hello world say hello world And another variation on infix assignment:} know {[lindex $args 1] == "="} { set name [lindex $args 0] set value [lrange $args 2 end] if [catch {uplevel 1 set $name [expr $value]} res] { uplevel 1 set $name [list $value] } else {set res} } puts [i = 17] puts [j = $i + 4] But as in [radical language modification], this works only for variable names that are unknown as commands... ---- This is pure and utter evil. I ''like'' it! ---- I have wondered how hard it would be to connect unknown to a database or even a socket that would serve as the source for unknown procedures. I was thinking about how a local client can be customized to match a remote server. In the two cases I am considering, the code that defines the procedures for editing data in a data base could be in the data base itself. When the client runs and needs to access a table that is defined (in the data base) but not previously accessed it would go to a data base table of tcl code (accessed using the table name as the key) and ''somehow'' get the code into the interpreter. I was looking at the pkgIndex file and was wondering about what would happen if the code [list source .....] was replaced with something besides source that would load code. Then I wondered, what ''is'' the equivalent of '''source'''? That is, if I have a string containing tcl code that is equivalent to the contents of a file of tcl code, what is the proper way to load it? In the second case, instead of having the source code in a data base, the source would reside on a remote system. I would want to dynamically load it through a socket. (This sounds similar to the interface between [Erlang] and Tk.) So ''somehow'' unknown would need to do these steps: 1. Inquire through a socket whether the remote system had a definition for a proc 1. If it did, then transfer it through the socket. 1. If it was received successfully, load it. Is this kind of behavior a ''solved problem'' somewhere? ''[escargo] 5 Nov 2002'' [RS]: To evaluate a string, use [eval] of course ;-) ''source $file'' does basically: set fp [open $file] set data [read $fp] close $fp eval $data So if you get your code over a network, just [eval] it (but maybe in a safe interpreter...) [escargo]: I was sure it was something simple like that, but [eval] is not mentioned on the [source] page (although ''evaluate'' is). ---- [unknown] - [Arts and crafts of Tcl-Tk programming]