Explicit TCE

Tyler Jameson Little beatgammit at gmail.com
Fri Oct 12 11:42:14 PDT 2012


On Friday, 12 October 2012 at 18:02:57 UTC, bearophile wrote:
> Tyler Jameson Little:
>
>> D could use something like Newsqueak's become keyword. If 
>> you're not familial with Newsqueak, become is just like a 
>> return, except it replaces the stack frame with the function 
>> that it calls.
>
> Are you talking about CPS?
> http://en.wikipedia.org/wiki/Continuation_passing_style

I don't think it would necessitate CPS, but that is a nice side 
effect. I'm thinking more of a recursive function call that may 
or may not return. For example, a process that shovels data 
between two network connections. If the data never stops, the 
function will never return. If there's some kind of a problem, 
then it could return with that error, and be restarted when that 
problem is fixed. All of this could happen with a series of 
function calls that use the same stack.

void handleIncommingData() {
    if (error) {
        // returns directly to manageLongRunningProcess
        return;
    }

    // do something useful

    become longRunningProcess();
}

void longRunningProcess() {
     become handleIncommingData();
}

void manageLongRunningProcess() {
     longRunningProcess();
     // there was a problem, so fix it
     ....

     // try again
     manageLongRunningProcess();
}

Exceptions are not needed, so these can be nothrow functions, and 
this implementation is simpler than some complex while loop, 
while having the same memory footprint.

CPS would make things like imitating javascript's 
setTimeout/setInterval possible. I don't think this is a major 
benefit for D because the parallelism/concurrency support is 
already pretty awesome.

The main benefit is for implementing things like lexical 
analyzers (or tokenizers, whatever), which don't really depend on 
previous states and can emit tokens. This allows for efficient 
representation of recursive problems, that call functions 
circularly (a -> b -> c -> a -> b ...), like a state machine.

I think it just allows an extra level of expressiveness without a 
backwards incompatible change to the language. True, you can 
express this same idea with trampolining, but that isn't as fun:

http://stackoverflow.com/a/489860/538551
http://en.wikipedia.org/wiki/Tail-recursive_function#Through_trampolining

There are still some problems that I think a LISP language would 
make more sense for, and for those problems, it would be great to 
express them in D with my other code.

>> DMD should optimize this already, but explicitly stating 
>> become is a key to the compiler that the user wants this call 
>> to be eliminated.  Then, more interesting things can be 
>> implemented more simply, like a state machine:
>>
>>    void stateA() {
>>        become stateB();
>>    }
>>
>>    void stateB() {
>>        become stateC();
>>    }
>>
>>    void stateC() {
>>        return;
>>    }
>>
>>    void main() {
>>        become stateA();
>>    }
>
> Seems nice.

I'm glad you think so =D

>> I'm not sure how D handles stack sizes, so this may be an 
>> issue as well if stack sizes are determined at runtime.
>
> D doesn't currently support C99 VLAs, but it supports alloca(), 
> so stack frames are sized dynamically. But maybe this is not a 
> big problem for CPS.

Well, dynamic stack frames aren't strictly a bad thing for CPS, 
it just removes the memory use guarantee. There's already a huge 
memory gain from using TCE, I just don't know debugging would be 
done if a function keeps adding to and passing a dynamic array.


More information about the Digitalmars-d mailing list