Resources and Streams
Keep resource ownership scoped and stream failures explicit.
Scoped Ownership
with owns a resource and closes it on scope exit, including early failure and cooperative cancellation. File handle capabilities describe which operations are available.
import:
fs: IOError, open_read, read_text
func load_text(path: String) -> Result[String, IOError]:
with reader ?= open_read(path):
reader.read_text()
Handles Stay in Scope
Resource handles cannot escape in ordinary records, collections, return values, or closure captures. Return ordinary data instead.
import:
fs: FileReader, IOError, open_read
func leak_reader(path: String) -> Result[FileReader, IOError]:
with reader ?= open_read(path):
Ok(reader)
One-Shot Streams
A stream is a cursor, not a reusable collection. Build its pipeline in local bindings and consume it once. Fallible terminals return Result, so read failures cannot disappear into an ordinary for loop. Create and consume the cursor inside the scope that owns its handle.
import:
fs: IOError, lines, open_read
stream: count_result
func line_count(path: String) -> Result[Int, IOError]:
with reader ?= open_read(path):
reader
.lines()
.count_result()
Typed Errors
Map resource errors into your application's error type at the boundary.
import:
fs: message, open_read, read_text
union AppError:
Io(String)
func load_text(path: String) -> Result[String, AppError]:
with reader ?= open_read(path) on err => Io(message(err)):
match reader.read_text():
Ok(text):
Ok(text)
Err(err):
Err(Io(message(err)))
Connection Ownership
A TCP connection source transfers each accepted stream into its own scoped loop body. Bounded concurrent iteration gives each child exclusive ownership and joins the work before the enclosing scope exits. The source borrows its listener. This is an ownership example, not a durable server: connections_stop_on_error ends on any accept error, including an idle timeout, without returning it from the loop. The function's Err covers listener setup; peer errors are logged, and child task results are not collected. connections_continue_on_error retries accept timeouts only; other errors still end iteration. Use explicit accept when you need its error result, and choose an error and shutdown policy for a real server.
import:
net/tcp:
IpFamily(IPv4),
TcpError,
connections_stop_on_error,
listen_loopback_any_port,
read_chunk,
set_stream_timeout,
set_timeout,
units: seconds, to_timeout_milliseconds
-- Scoped ownership/policy example, not a durable server.
-- Err reports listener creation/configuration errors, not loop/peer failures.
func connection_ownership_example() -> Result[Void, TcpError]:
with listener ?= listen_loopback_any_port(IPv4, 64):
configured ?= set_timeout(listener, to_timeout_milliseconds(seconds(1)))
-- An accept timeout or other accept error ends iteration without propagating.
-- Each accepted peer moves into one child, which owns its scoped cleanup.
for peer in connections_stop_on_error(listener) concurrently(limit: 2, timeout: seconds(2)):
match set_stream_timeout(peer, to_timeout_milliseconds(seconds(1))):
Ok(_):
match read_chunk(peer, 4096):
Ok(data): print("received ${data.length()} bytes")
Err(error): print_error(error)
Err(error):
print_error(error)
-- Peer I/O errors are logged above; child task results are not collected.
Ok(void)