Version 14 of tailcall

Updated 2009-11-07 08:07:59 by wdb

Like uplevel 1 except that it also causes the current scope to terminate, though the command is looked up in the current context first. Consequence of NRE.

 proc fred {} {
     george
 }

proc 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 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... jima 2009-10-15: Perhaps this has been asked before or somewhere else...

I mean, once fred knows that has to call harry directly the bytecodes generated 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 As of today tailcall is not byte compiled, everything happens at runtime. That extremely simple example could indeed be bytecoded in a minute, but things get more involved as soon as [fred] has a bit more structure to it: arguments, local variables, namespace issues both for variable and command lookup, multiple exit points with different (or no) tailcall in them, etc. jima: Thanks a lot Miguel for the answer. I see the point. I guess this is jima: Thanks a lot Miguel for the answer. I see the point. I guess this is 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 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, especially to accomodate Tcl's dynamic nature. Changing one inlined proc would cause a spoiling of all bytecodes and recompilation of the world, at least with the current approach to bytecode lifetime management.

AMG: Sounds a lot like exec in Unix shells. AMG: Sounds a lot like exec in Unix shells. See execline for more


See also TIP#327


Interaction with try

% 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? wdb: Apparently, the tailcall closes one of the last gaps in wdb Appearantly, the command tailcall closes one of the last gaps in Tcl: Tail recursion as known in Scheme