# IO
The I/O verbs are bare stdlib functions compiled into every Deft runtime —
the `deft` scripting binary and the TUI hosts alike. They operate on
channels: `open` returns an opaque `%Chan` handle, and `puts` / `gets`
read and write through it. See Filesystem for whole-file and
path helpers, and Syntax and Style for
the call forms.
## Functions
| Function | Purpose |
|---|---|
| `echo $args...` | Print values to stdout followed by a newline |
| `puts ?target $value` | Write a line to a channel (default `:stdout`); strings raw, other values formatted like `echo` |
| `gets ?target` | Read a line from a channel (default `:stdin`); nil at EOF |
| `open "path" ?mode` | Open a file as an opaque `%Chan` (`"r"`/`"w"`/`"a"`/`"rw"`); `%Err` on failure |
| `close $chan` | Close a channel; true if this call closed it, false if already closed |
| `log $args...` | Append values to `<tmp>/deft.log` (bypasses capture) |
Channel targets are `%Chan` handles from `open` or the `:stdin` / `:stdout`
/ `:stderr` keywords — raw file descriptors are never values. Descriptors
are process-global, reusable, and un-GC-able, so a bare fd number passed to
`puts`, `gets`, or `close` is rejected. Channels are closed explicitly with
`close` or automatically by the GC when a dropped handle is collected; the
standard stream keywords themselves cannot be closed (passing one raises).
### Notes
- `echo` always writes to stdout, one line per call. Strings are emitted
raw; other values are formatted for display.
- `puts` writes `$value` and a newline to the target channel. Strings go
out raw; other values are formatted exactly the way `echo` formats them.
- `gets` returns the line without its trailing newline, or `nil` at end of
file (a final line without a newline is still returned). It blocks until
a line arrives — on a TTY inside a hosted TUI app that stalls the panel.
- `open` modes are `"r"` read (the default), `"w"` write (truncates), `"a"`
append, and `"rw"` read/write. An unknown mode raises; an unopenable path
returns `%Err{:message}`, so check with `err?` before using the handle.
- `close` is idempotent: the first call returns `true`, later calls
`false`. Closing a standard stream raises.
- `log` is the bare disk logger: it appends formatted, space-separated
values and a newline to `<tmp-dir>/deft.log`, bypassing TUI redirects and
the echo capture buffer — it writes to disk in every host. For levelled
output gated by `DEFT_LOG_LEVEL`, use `log/debug`, `log/info`, `log/warn`,
and `log/error` from Logging.
## Examples
### Write and read a file
set path "/tmp/deft-io.txt" set out [open $path "w"] puts $out "first line" puts $out "second line" close $out set in [open $path] # mode defaults to "r" while true { set line [gets $in] if [nil? $line] { break } echo "read:" $line } close $in
### Streams and the disk log
echo "to stdout" puts :stderr "diagnostic to stderr" set out [open "/tmp/deft-io.txt" "a"] # append puts $out "appended entry" close $out log "checkpoint reached:" 17
`puts` with no target writes to `:stdout`, so `puts $value` is equivalent
to `puts :stdout $value`.
## See Also
- Filesystem
- Logging
- Utility
- Syntax and Style