There seem to be a lot of implementations of the same concept around, that is transforming code to an asynchronous state machine. See my comment at a previous thread [1]. Some implementations not mentioned in this submission are TameJS (for Javascript) [2] and CPC (Continuation Passing C) [3]. It would be interesting to see more comparisons of those, especially Protothreads and CPC, both working on top of C(++).
I especially like how in C# this asynchronous mode of execution is part of the language itself, and no code transformation tools (or macros) are necessary on the user end. I think this makes it much more accessible, both because it's immediately available, and because it avoids fragmentation. See also my NCD programming language [4], where asynchronous execution is an essential feature of the language.
Protothread is really just a set of macros, based of Duff's device, to make it easier to write automata in a threaded style. It has many limitations: it does not automatically save local variables, it does not compose (except when using "hierarchical protothreads", which involves rewinding the whole stack on every cooperation point), etc. Section 5.3 of Dunkels et al.'s paper states that these are only limitations of the "current protoype", but I am not aware of any implementation of protothreads solving these issues at all (except if you consider CPC a full-fledged implementation of Protothreads, done correctly ;-).
Protothreads is a hack, a maybe clever hack, but a hack nonetheless. CPC, on the other hand, is an extension of the C language, compiled to C by proven source-to-source transformations. Of course, you then have to pay the cost of the added dependency (protothreads is only a bunch of C files to include), and potential bugs in the translator.
Creator of protothreads here. Protothreads are not a hack.
Protothreads revolve around the concept of local continuations. Unlike traditional continuations, a local continuation only captures the state of execution within the local function in which they are created. I.e., a local continuation does not contain the call stack. This makes it possible to do things like invoking protothreads from multiple call paths.
The "hack" you refer to is just one possible implementation of the protothread concept, in which the local continuations are implemented by a switch statement in the spirit of Duff's device. This implementation technique allows the protothreads library to be implemented in only 7 lines of code (!) but it has a bunch of drawbacks, such as not recording the state of local variables. In fact, because of these drawbacks, the switch-based implementation arguably does not provide a fully functional version of protothreads.
There are other ways to implement protothreads. The original protothreads library contains an implementation where the local continuations are done using gotos and gcc's labels-as-values feature. This does remove some of the problems with the switch statement, but still does not record local variables. Others have implemented protothreads in C++, where a class object is used to store local variables, and by adding a C2C wrapper compiler that produces C code that stores and restores the local variables.
Protothreads were created to explore some of the finer points in the twilight zone between multithreading/coroutines and events/state machines. The intent was never to emulate continuations, coroutines, or threads but to find a less expensive way to achieve linear code flow. With protothreads, linear code flow can be achieved without having to store multiple thread stacks, which is important in many of the systems for which protothreads were originally intended. The switch-based implementation also has the added benefit of being possible use with any C compiler, which has been very useful as we have ported Contiki to a bunch of different platforms and C compilers.
But, yeah, the switch-based implementation of the protothreads concept can definitely be labelled as a hack. But - admit it - a beautiful hack! :)
Yes, they're a hack, but this is HACKer News, right? :-) More correctly, though, as Adam pointed out, the switch statement implementation of protothreads is a hack.
However, I'd like to also point out that it's a very useful hack. In the tiny embedded micros I work with, something like CPC would be much too heavy weight. Protothreads take 2 bytes of RAM per "thread", and you can even get that down to 1 byte if you use __COUNTER__ instead of __LINE__. Protothreads also have the huge advantage of working in regular C and C++, meaning standard tools just work.
Even more so, over the years I've seen in the wild and had cause to roll similar multiple entry points to functions, so standard practice predates both those dates by a decade or two. It is always good to see it written down to share the idea to the next generation.
CPC is something I've longed for in the past. I've always thought C could do with just a couple more features related to function call and frame management to make it the ideal portable low level language.
I especially like how in C# this asynchronous mode of execution is part of the language itself, and no code transformation tools (or macros) are necessary on the user end. I think this makes it much more accessible, both because it's immediately available, and because it avoids fragmentation. See also my NCD programming language [4], where asynchronous execution is an essential feature of the language.
[1] http://news.ycombinator.com/item?id=4736630
[2] http://tamejs.org/
[3] http://www.pps.univ-paris-diderot.fr/~kerneis/software/cpc/
[4] http://code.google.com/p/badvpn/wiki/NCD