[Keith Vetter] 2018-05-03: One feature I miss in Tcl that Python has is the easy ability to wrap functions. I've twice recently felt the need for this. The first time I wanted the same argument handling of https://core.tcl.tk/tips/doc/trunk/tip/176.md%|%Tip 176%|% i.e. being able to pass M+N. The second time when I wanted to memoize a function for dynamic programming. Both of these can be solved by adding code to the start of your function--the [memoize] page has a slick function to do just that. But to my mind, a conceptually cleaner solution is to leave the function intact and just transform it by wrapping it. In Python this transformation is done with decorators [https://www.python.org/dev/peps/pep-0318/] [https://realpython.com/primer-on-python-decorators/], and it uses the eye-catching ''pie'' syntax: ====== @memoize def my_function(a, b): return a+b ====== Once you start thinking of decorators, new uses keep coming up: insuring you're logged in, running only in test mode, timing functions, synchronization, automatic logging, etc. [https://stackoverflow.com/questions/489720/what-are-some-common-uses-for-python-decorators] So I decided to see if I could write a Tcl version of a decorator for memoization and automatically processing arguments, ala tip 176. After some serious quoting issues and a good use of [apply] I came up with the following solutions. ====== proc @memoize {p pname pargs lambda} { if {$p ne "proc"} { error "bad synax: $p != 'proc'"} proc $pname $pargs " set cmd \[info level 0\] if {\[info exists ::MEM(\$cmd\)\]} { return \$::MEM(\$cmd) } set argVals \[lmap var {$pargs} {set \$var}] set ::MEM(\$cmd) \[apply {{$pargs} {$lambda}} {*}\$argVals\] " } # Test @memoize \ proc test_@memoize {a b} { puts "in test_@memoize $a $b" return $a } test_@memoize 1 2 test_@memoize 1 2 proc @auto_index {p pname pargs lambda} { if {$p ne "proc"} { error "bad synax: $p != 'proc'"} proc $pname $pargs " set argVals {} foreach arg {$pargs} { set val \[set \$arg\] if {\[regexp \{^-?\\d+\[+-\]-?\\d+$\} \$val\]} { set val \[expr \$val\] } lappend argVals \$val } apply {{$pargs} {$lambda}} {*}\$argVals " } # Test @auto_index \ proc test_@auto_index {a b c} { puts "a is $a and b is $b and c is $c" } test_@auto_index hello 3 4+5 ====== <>Enter Category Here