# 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