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.