In Wuffs, coroutines are functions that can suspend their execution in the middle of the function body, yielding (returning) a status that is a suspension. Calling that function again will resume that function where it left off. Calling any other coroutine function on the same receiver, whilst it is suspended, will result in an error.
Unlike coroutines in other programming languages, Wuffs coroutines cannot return other values in addition to that status, and statuses don't carry additional fields. Wuffs coroutines cannot be used as generators directly, although they can produce to and consume from buffers as side effects. The built-in I/O types (base.io_reader
and base.io_writer
) have coroutine methods that are exceptions to this “no additional return value” rule, and are special-cased by the Wuffs compiler.
Another difference with other programming languages is that Wuffs coroutines' arguments can change across a suspension and resumption. The mechanism for resuming a coroutine, for C code that calls into Wuffs-transpiled-to-C, is to simply call the C function again, with the same self
receiver (the first argument), but with potentially different other arguments.
As of Wuffs version 0.2 (December 2019), the language and standard library use only two suspension status values, both I/O related: "$short read"
and "$short write"
are used when a source buffer is empty (and needs re-filling) or a destination buffer is full (and needs flushing). These I/O related suspensions, together with the I/O buffer arguments' contents and read/write indexes changing, are how compression decoders are able to decompress from arbitrarily long inputs to arbitrarily long outputs with fixed sized buffers.
Wuffs coroutines are stackful, in that they can call other coroutines, although not recursively. When suspended, coroutine state is stored in the receiver struct. Wuffs has no free standing functions (and therefore no free standing coroutines), only methods (functions with a receiver).
Wuffs code (as opposed to a C program calling into a Wuffs library) can only call coroutines from within a method that is also a coroutine. If the callee suspends, then the caller will also suspend, by default, unless the callee's status result is assigned via the =?
operator.
Syntactically, coroutines are marked by a question mark, ?
, at their definition and at call sites, implying that their return type is a base.status
. The yield
keyword is also always immediately followed by ?
, so that grepping a function's body for the literal question mark will find all of the potential suspension points.
As for facts, crossing a potential suspension point drops any facts involving this
or args
. Facts only involving local variables are preserved.