# deftask
Create an async task — a Future or stream depending on the body's decorators.
## Syntax
[deftask { body }] # run body on a fresh OS thread
[deftask { @parallel body }] # explicit equivalent of the default
[deftask { @stream body }] # stream of incremental results
[deftask { @stream @buffer-size 128 body }] # stream with custom buffer
A plain `deftask` is parallel by default: the closure's bytecode is
deep-copied into a fresh runtime on a new OS thread, and the call returns a
pending Future. `@parallel` is accepted as an explicit marker for the same
behavior.
Mode decorators are carried as decorator metadata on the closure — the
same `@`-decorator mechanism defs use (`@async`, `@generator`, `@rpc`). Put
them at the top of the body, each on its own line or separated by `;`:
[deftask {
[http/get "https://api.example.com/a"]
}]
[deftask { @stream; yield 1 }]
## Decorators
| Decorator | Effect |
|-----------|--------|
| `@parallel` | Explicit form of the default: deep-copy the closure's bytecode into a fresh runtime on a new OS thread; returns a pending Future. |
| `@stream` | Run the body on a new OS thread; `yield` values are pushed into a buffered stream. |
| `@buffer-size N` | (with `@stream`) Stream buffer size (default 64). |
Task bodies must be self-contained: native stdlib functions are available, but
captured locals and user-defined functions do not cross into the child
runtime. (For full module access use `defworker`.)
## Examples
def x 6 # global — snapshotted into the child runtime def fut [deftask { ($x * $x) }] echo [await $fut] def ps [deftask { [http/get "https://api.example.com/a"] }] [await $ps] def s [deftask { @stream @buffer-size 128 yield 1 yield 2 yield 3 }] set row [task/stream-next $s] while (not [nil? $row]) { # ... process $row ... set row [task/stream-next $s] } # or just: def rows [task/stream-collect $s]
## Returns
A Future (`deftask` / `@parallel`) or a stream (`@stream`).
## Errors
How a throw inside the task body surfaces depends on the mode:
- `deftask` / `@parallel` — the future resolves with the error string
(e.g. `"boom (line 1)"`); `await` returns it as the task's value. It does
not re-throw at the await site.
- `@stream` — the stream simply ends; the error is swallowed.
set v [await $f] if [is? "string" $v] { echo "task failed:" $v }
## See Also
`await`, `spawn`, `resume`, `async`, `defworker`