''Please stop me if you've heard this one before...'' What would it take to add a ''macro'' facility to Tcl? What use would such a facility be? Well, for starters, it would make syntatical sugar (attrocities) such as: proc first {l} { lindex $l 0 } proc rest {l} { lrange $l 1 end } cost less in terms of performance. Yes, yes, I know -- if performance really mattered I shouldn't be doing this in Tcl. But the difference between calling my own procs vs internal ones (especially in deep loops) count, right? Well, what about ''immediate'' macros (or macros that have a compile time behavior). Common Lisp should come to mind, but I can't help thinking about Forth ''immediate'' words. So, I could do something like: mac log {msg} { global debug if {$debug} { return "puts stderr $msg" } else { return "\;" } } and use it thusly: set debug 0 ... proc something {} { set stuff "contents not available for introspection by macro yet." log "Some noise I may not want to see depending on the value of debug" log $stuff; # if debug was 1, then the macro would expand to: puts stderr $stuff ... } The above assumes that I have redefined ''proc'' to point to a macro evaluator to execute all macros before actually defining the ''real'' proc. The return value of the macro evaluation is what replaces the macro in the procedure. In this example, I can do conditional compilation! This could all be done in plain Tcl if I gave Tcl access to the Tcl C parser code (to properly locate the arguments for the expanding macro). Note: You are limited by what context is available when executing the macro (you can for instance look into the surrounding proc's variables since we are in ''compile'' mode --- there aren't any values for the variables yet so the arguments to the macros are not eval'd!). Another use for an ''immediate'' macro facility: mac mloop {idx cnt cmd} { return "for {set $idx 0} {\$[set $idx] < $cnt} {incr $idx} {$cmd}" } proc something {} { mloop i 5 {puts "hello $i"} # above expands to: for {set i 0} {$i < 5} {incr i} {puts "hello $i"} } My mind is often polluted by such sickness... -- [Todd Coram] ---- Well the log use of macro you had above looks like an assert function, which I believe has been addressed by cleverness in the core that optimizes null functions out of existence. I've used macros in a cpp-ish fashion, to eliminate big repeated blocks of code. Here's the macro function I wrote: # procedure to create macros that operate in caller's frame, with arguments # no default args yet proc macro {name formal_args body} { proc $name $formal_args [subst -nocommands { # locally save all formal variables, and set them in parent conext foreach _v [list $formal_args] { if {[uplevel 1 info exists \$_v]} { set __shadow__\$_v [uplevel 1 set \$_v] } uplevel 1 set \$_v [set \$_v] } uplevel 1 { $body } # undo formal variables foreach _v [list $formal_args] { if {[info exists __shadow__\$_v]} { uplevel 1 set \$_v [set __shadow__\$_v] } else { uplevel 1 unset \$_v } } }] } So you can do something like set text "hello" macro foo {a} { puts "$text $a" } foo world foo everybody => hello world hello everybody Of course this makes more sense when the body of the macro is 70 lines long and its used in 8 different files, so it replaces a whole bunch of identical (except for a few bits) code with something alot more readable. ---- [RS] has devised this very simple argument-less "micro-macro" instigated by [Literate programming in a wiki]. Beware that spaces in proc names, as implemented here, may at some time in the future be no more possible: proc @ {name {body -}} { if {$body!="-"} { proc $name {} [list uplevel 1 $body] } else {uplevel 1 [list $name]} } # Macro definitions: @ "Prepare input" {set x 2} @ "Produce result" {puts [expr sqrt($x)]} # Macro testing: % @ "Prepare input" 2 % @ "Produce result" 1.41421356237 [jcw] is more data oriented than procedural, and adds: proc @ {name {body -}} { global snippets if {$body!="-"} { set snippets($name) $body } else { uplevel 1 $snippets($name) } } ----