[upvar 1] and [uplevel 1], which, respectively, link a variable in your caller's stack frame to one in yours and run a command in the caller's stack frame, usually compose nicely. They are Tcl's replacement for macros and the lack of a compile time/run time distinction makes them, in a way, easier to reason about. However, [upvar N] and [uplevel N] aren't limited to N = 1, your immediate caller's stack frame. You can reach up an arbitrary number of stack frames. It allows you to design really complicated control structures. [upvar] links also nest. You can fall into a pattern of carrying around some sort of a context or configuration data with nested [upvar]s like a poor man's Reader monad. Both are difficult to debug when they go wrong and should be implemented with care and only when necessary.
Since version 8.5 Tcl has a built-in command for assigning list elements to variables:
lassign [procedure arg1 arg2] resultpart1 resultpart2
Conveniently, it also returns the remainder of the list if there were more list elements than variables. It leads to the idiom set list [lassign $list foo bar baz]
I have a strange test for languages - I tried some of them being drunk (a litre of some nice tripel). This test tests how effective can you be with diminished higher-order thinking, or, in other words, how much of your mental ability each tested language takes from you.
Tcl has immutable proc arguments - if you pass somewhere a value you can be sure the value at caller's site stays the same. It happened that this means a lot and one can (semi)successfully program in Tcl while being drunk.
Every language where arguments' values modification is visible to the caller is much worse in that regard, these are C, C++, C#, Java, Python and Perl (and many more). Aother bad feature is a null pointer - Per is better here.
Tcl does not have modifiable argument values except you are really want them (upvar and uplevel). It also has multivalue assignment in the form of "foreach {resultpart1 resultpart2} [procedure arg1 arg2] break" (or you can invent your own mutivalue assignment procedure). This makes building composable libraries quite easy.