# Tasks
The `task/` verbs are the consumer side of the asynchronous handles
produced by `deftask`: a plain (parallel) task returns a Future that
settles to one value, while `@stream` returns a stream that delivers
incremental values as the producer yields them. `spawn` starts
cooperative coroutines, the sibling model in
Concurrency. These functions read, poll,
and close task handles; all are native stdlib, available without an
import.
## Functions
| Function | Purpose |
|---|---|
| `task/stream-next $s` | Block for the next stream value; `nil` when the stream is exhausted |
| `task/stream-collect $s` | List of all remaining stream values |
| `task/stream-try-next $s` | Non-blocking read; `nil` immediately when no value is ready |
| `task/stream-close $s` | Signal that the consumer is done reading; `nil` |
| `task/stream-done? $s` | `true` when the producer has finished (no more values will arrive) |
| `task/future-ready? $f` | `true` when the future is settled (resolved or rejected); never blocks |
Notes:
- Stream producers run on their own OS thread with a buffer
(`@buffer-size N`, default 64). `stream-done?` reports producer
completion, not buffer emptiness: after the producer has finished,
values still buffered can be drained with `stream-next` or
`stream-collect`. Use `stream-try-next` to interleave a stream with
other work, and the blocking `stream-next` when you are ready to
consume.
- `stream-close` releases the consumer end; it does not kill the
producer.
- `future-ready?` only reports state — call `await` for the value. A
task that threw still settles: `deftask` futures resolve with the
error string, so a ready future is not necessarily a successful one.
- A stream whose body throws simply ends; the error is swallowed and
the consumer sees the stream finish.
## Examples
# Blocking consumer loop — stream-next returns nil when exhausted def s [deftask { @stream yield "a" yield "b" yield "c" }] set row [task/stream-next $s] while ![nil? $row] { echo "got" $row set row [task/stream-next $s] } # Non-blocking poll, then a bulk drain def s2 [deftask { @stream; yield 1; yield 2; yield 3 }] set first-value [task/stream-try-next $s2] # value, or nil if not ready [task/stream-done? $s2] # => true once the producer is done def rest [task/stream-collect $s2] # buffered remainder [task/stream-close $s2] # Futures settle independently of the consumer def f [deftask { (6 * 7) }] [task/future-ready? $f] # => false — still running [await $f] # => 42 [task/future-ready? $f] # => true — settled
Because `stream-collect` returns a list, the result feeds straight into
the sequence functions from Sequence Functions —
`map`, `filter`, `reduce` — or into `await`-style coordination when the
producer is paired with other tasks.
## See Also
- Concurrency — `deftask`, `@stream`, `spawn`, `await`
- Sequence Functions — processing collected stream values
- Lazy Sequences — the pull-based alternative