Meta-programming is the writing of code that writes itself.
Tcl has lots of support for meta-programming:
Meta-programming is not widely accepted as a programming technique, probably because it allows self-modifying code, which many people view as a bad thing. How can we take advantage of meta-programming to improve the performance and structure of Tcl (or other) code? See also How to change a running system for discussion how a Tcl interpreter is self-modifying from the very start.
Advantages of Meta Programming
Metaprogramming can often involve more than one level of quoting and interpretation. Here is a bit of code to make this easier by using a template procedure. -- Mark
proc makeTemplate {procname templatename parmlist} { set arg [info args $templatename] set body [info body $templatename] foreach {a b} $parmlist { regsub -all $a $body $b body } eval "proc $procname {$arg} {$body}" } proc FooTemplate {a b} { puts "MSG1" puts "hello, $a, $b" puts "MSG2" } makeTemplate foo1 FooTemplate {MSG1 "hello world!" MSG2 "goodbye!"} makeTemplate foo2 FooTemplate {MSG1 "hi!" MSG2 "bye!"} foo1 mom dad foo2 breathren cistern
Links about Meta Programming in Tcl
Duplicating Procedures (Emmanuel Frecon)
I have used dynamic duplication of procedures in several projects and found this very useful:
proc html_hbar { fdes { size -1 } { alignment "LEFT" } } { puts -nonewline $fdes "<HR " if { $size >= 0 } { puts -nonewline $fdes "width=\"$size%\" " } puts $fdes "align=\"$alignment\">" } ... proc conversion_init { } { foreach procname { hbar } { set args {} foreach a [info args html_$procname] { if { [info default html_$procname $a deft] } { lappend args [list $a $deft] } else { lappend args $a } } uplevel \#0 [list proc output_$procname \ $args [info body html_$procname]] } }
This code would lead to the procedure "output_hbar" being declared identical as the procedure "html_hbar". Note the use of the "info default" to make sure that procedure with default arguments can still be called with less than all the arguments. If you don't do this, you will end up with procedures that require all the arguments when called.
DKF: You can use interpreter aliases to do this sort of thing as well. Furthermore, you can use them to supply leading arguments to do some very cute things. Leading on from the above...
proc HTML {fdes script} { global errorInfo errorCode namespace eval HTML_EVAL {} foreach procname [info commands html_*] { regsub html_ $procname HTML_EVAL:: aliasname interp alias {} $aliasname {} $procname $fdes } set code [catch {namespace eval HTML_EVAL $script} msg] namespace delete HTML_EVAL return -code $code -errorcode $errorCode -errorinfo $errorInfo $msg }
"Outside" references on the topic include: