# 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