** Summary ** Like `[[[uplevel] 1]` except that it also causes the current scope to terminate, though the command is looked up in the current context first. Made possible by [NRE]. [wrapping commands]: wrap commands by using `[interp invokehidden]` together with `tailcall` ** Synopsis ** : '''tailcall''' ''command'' ?''arg''...? '''`tailcall`''' interprets its arguments as a command and executes the While `[[[uplevel]]` takes a script, [[tailcall] takes a command. If you want to [[tailcall] a script do it as follows: tailcall try $script ====== ---- This is discussed at the bottom of the page, but worth mentioning here for quick reference. [WHD]: Let me see if I understand what this does. ====== proc fred {} { george } proc george {} { tailcall harry } ====== If I call fred, it's almost as though fred called harry directly, instead of george. Not so? [MS]: yup - all traces of george are gone from the program stack when harry is called. Now, if harry resolves to a different command in george's current namespace than it would under fred's, the harry that is called is george's and not fred's (no diff if the commands are FQ, of course). I think this does pretty much what delegation is supposed to do, right? ---- [jima] 2009-10-15: Perhaps this has been asked before or somewhere else... Is this an optimization that takes place at bytecode generation time? I mean, once fred knows that has to call harry directly the bytecodes generated would be the ones equivalent to have said: ====== proc fred {} { harry } ====== I reckon I am not familiar with all the internals of Tcl but I find this would be an interesting thing. Wouldn't this be a new way to have some sort of macros? [MS]: Currently, `tailcall` is not bytecompiled. Everything happens at [MS]: Currently, [[tailcall] is not byte compiled. Everything happens at but things get more involved as soon as `fred` has a bit more structure to but things get more involved as soon as `[[fred]` has a bit more structure to lookup, multiple exit points with different (or no) `tailcall` in them, lookup, multiple exit points with different (or no) `[[[tailcall]]` in them, [jima]: Thanks a lot Miguel for the answer. I see the point. I guess this is the same with `[uplevel] 1`, isn't it? the same with `[[[uplevel] 1]]`, isn't it? ====== proc fred {} { uplevel 1 { #code here } } ====== Would it be interesting to define a case (like a contract) saying if your proc is simple enough then it gets bytecompiled and you get some benefits? [MS]: you do not mean "bytecompiled" but rather "inlined into the caller", as all `[proc]` bodies get bytecompiled. There are quite a few other issues with that, all `[[[proc]]` bodies get bytecompiled. There are quite a few other issues with that, cause a spoiling of all bytecodes and recompilation of the world, at least with the current approach to bytecode lifetime management. the current approach to bytecode lifetime management. ---- [AMG]: Sounds a lot like `exec` in [Unix shells]. See [execline] for more information on a noninteractive Unix shell where everything is done with exec/tailcall. ---- See also [TIP]#[http://tip.tcl.tk/327%|%327] *** Interaction with `[[[try]]` *** ---- '''%''' proc foo {} {puts {I'm foo}} '''%''' proc foo {} {puts "I'm foo"} '''%''' proc bar {} {puts "I'm bar"; try { tailcall foo } finally { puts "exitting" }} ''I'm foo'' '''%''' bar ''I'm bar'' ''exiting'' ''exitting'' === 31-03-2015 [HE] I'm sure ;-) that I don't understood what happend there. Why "exiting" is printed before "I'm foo" when I call bar? [AMG]: [[foo]] is invoked by replacing [[bar]] which implies the intervening [[[try]]] block must exit before [[foo]] can start. [wdb]: Apparently, the `tailcall` closes one of the last gaps in [wdb]: Apparently, the command `[[[tailcall]]` closes one of the last gaps in ** Emulation ** [NEM]: As a test/demo of how to use this facility, here is a simple benchmark [Lars H] 2010-05-09: As of late, when writing an `[[[uplevel]]`, I've sometimes found myself thinking "That would be slicker with `[[[tailcall]]`, but I can't however use a `[proc]` to emulate the properties of `tailcall` that would however use a `[[[proc]]` to emulate the properties of [[tailcall] that would The main situation I've encountered is that of delegating to another command which may make use of `[upvar]` or `[uplevel]`. That's basically taken which may make use of `[[[upvar]]` or `[[[uplevel]]`. That's basically taken ====== proc utailcall args {uplevel 2 $args} proc utailcall {args} {uplevel 2 $args} although it's safer to make it ====== proc utailcall args {return -code return [uplevel 2 $args]} proc utailcall {args} {return -code return [uplevel 2 $args]} in case the "terminate proc early" aspect of `tailcall` is relied upon; this in case the "terminate proc early" aspect of [[tailcall] is relied upon; this Another aspect of `tailcall` is the name resolution of the called command. Another aspect of `[[tailcall]` is the name resolution of the called command. ====== proc ntailcall {cmd args} { return -code return [ [uplevel 1 [list ::namespace which $cmd]] {*}$args ] } ====== but it's almost as easy to do both at the same time ====== proc untailcall {cmd args} { return -code return [ uplevel 2 [list [uplevel 1 [list ::namespace which $cmd]]] $args ] } ====== A word of warning here is that this will produce a very confusing error message if the command is undefined, as `[namespace which]` returns an empty string if the command is undefined, as `[[[namespace which]]` returns an empty string A third aspect is that of preserving `[return]` levels. A third aspect is that of preserving `[[[return]]` levels. ====== proc rtailcall args { proc rtailcall {args} { dict incr options -level 2 return -options $options $result } ====== This leaves some extra material in the [errorInfo], but one can probably live with that. Combining the "r" and "u" aspects is straightforward, but will leave even more: ====== proc rutailcall args { proc rutailcall {args} { catch {uplevel 2 $args} result options dict incr options -level 2 return -options $options $result ====== To complete the set, one might just as well write down the combination of the "r" and "n" aspects ====== proc rntailcall {cmd args} { catch { catch { [uplevel 1 [list ::namespace which $cmd]] {*}$args } result options dict incr options -level 2 return -options $options $result ====== and of all three ====== proc rnutailcall {cmd args} { catch { catch { uplevel 2 [list [uplevel 1 [list ::namespace which $cmd]]] $args } result options dict incr options -level 2 return -options $options $result ====== But note: ''all of the above will fail if used for tail recursion'', as soon as the loops get long enough. ** Replacement for [[[uplevel]] ** [AMG]: `[uplevel]` has limitations with respect to [bytecode] compilation [AMG]: `[[[uplevel]]` has limitations with respect to [bytecode] compilation and interpretation of `[[[return]]`. If `[[[uplevel]]`'s level count is 1, and if it's the last thing being done in the `[[[proc]]`, these limitations can be avoided by using `[[[tailcall]]` instead. Note that `[[[uplevel]]` takes a script whereas `[[[tailcall]]` takes a command. If you want to pass a script to `[[[tailcall]]`, make it be the sole argument to `[[[try]]`. See [http://wiki.tcl.tk/1507#pagetocc0434a60%|%Possible uplevel deficiencies%|%]. Also see [http://wiki.tcl.tk/1507#pagetocb7539876%|%When to use uplevel] for more on when to use or avoid `[uplevel]`. See more on when to use or avoid `[[[uplevel]]`. See performance numbers regarding [bytecode] compilation with `[eval]`, performance numbers regarding [bytecode] compilation with `[[[eval]]`, `[[[uplevel]]`, `[[[try]]`, and others. ** When to apply `tailcall` optimization ** ------ ====== proc proc1 {arg1 arg2} { # do something here which finds arg3 and arg4 return [proc2 $arg3 $arg4] } ====== by ====== proc proc1 {arg1 arg2} { # do something here which finds arg3 and arg4 tailcall proc2 $arg3 $arg4 } ====== If proc2 is for sure found in the caller namespace? Is this an intelligent optimization? I came to this idea, as the TI C compiler calls this "tailcall optimization". [AMG]: Yes, except in a highly unlikely situation where `proc2` needs `proc1` to be visible in the stack. Procedures really ought not to care who called them, but Tcl makes all sorts of things possible, including stupid things. [AMG]: Yes, except in a highly unlikely situation where [[proc2]] needs [[proc1]] to be visible in the stack. Procedures really ought not to care who called them, but Tcl makes all sorts of things possible, including stupid things. <> Command | Control structure