Programming Language

Nocter

A self-contained systems language built around simplicity, encapsulation, and foolproof design.

/releases/v0.50.0.md

Nocter v0.50.0 Release Notes

Nocter v0.50.0 completes local-data access and asynchronous streaming as one bounded system. Applications can perform executor-safe file and filesystem operations, traverse directories, consume asynchronous item streams, transform them lazily, and connect local storage to generic file, process, network, TLS, and HTTP byte I/O.

This release replaces the previous blocking-only filesystem surface. Unqualified operations are asynchronous; explicit BlockingFile, BlockingReadDir, and _blocking operations remain for synchronous programs. No compatibility aliases preserve the old spelling.

Executor-safe Local Storage

File provides asynchronous open, create, append, read, write, flush, close, positioning, seeking, truncation, and positioned I/O. Filesystem functions cover metadata, links, canonicalization, copy, rename, creation, removal, directory streams, recursive removal, and recursive traversal.

Regular-file operations use a fixed-capacity blocking-job service rather than executing blocking syscalls on the executor thread. Each job owns any bytes and operating-system resources that target code may access. Cancellation and abandonment never retain pointers into a destroyed Nocter future, and completion publishes output only while the exact waiter still exists.

Asynchronous Iteration

AsyncIterator defines one fallible asynchronous next operation. for await consumes that contract with ordinary break, continue, return, propagation, and destruction behavior. Acquisition and dispatch are selected once during checking and carried through lowering.

use std/fs

let walker = await fs.walk_dir(root)?
var entries: usize = 0

for await entry in move walker {
    entries += 1
}

Lazy map, filter, take, and enumerate adapters transform items after acquisition without collecting the source. ByteChunks<R> reads explicit bounded chunks from any asynchronous Reader, and Lines<R> uses one bounded buffer with explicit maximum encoded-line length.

Generic Streaming Composition

The same Reader and Writer contracts connect files, process pipes, TCP connections, TLS connections, and HTTP response bodies. io.copy remains the single bounded byte-transfer algorithm. TimedReader and TimedWriter add a relative timeout to each operation without introducing an endpoint-specific protocol or copy loop.

Directory traversal retains a bounded depth-first stack and never materializes the complete tree. Recursive removal follows the same bounded traversal policy and does not follow final symbolic links. File copy compares the identities of already-open source and destination endpoints before mutation, preventing same-file aliases from truncating their source.

Complete Application

The new async-file-report example recursively discovers regular files, counts their bytes through 8 KiB chunks, and publishes a two-line report through a 4 KiB buffered file. The complete operation runs under one timeout. It closes the buffer and file before atomically renaming a sibling temporary file; recoverable failure or timeout removes the temporary output.

The example retains memory proportional to the bounded traversal depth and configured buffers, not to the total number or size of input files.

Editor and Compiler Support

Parser, formatter, declarations, checking, ownership, MIR, Machine lowering, diagnostics, hover, completion, signature help, navigation, semantic tokens, and inlay hints understand AsyncIterator, for await, and the standard streaming APIs through ordinary semantic identities. Editor features use the same checked application snapshot as command-line compilation.

Migration and Non-goals

Code using the old synchronous unqualified file or filesystem operations must use the explicit blocking form or await the canonical asynchronous form. Manual asynchronous directory loops may adopt for await; endpoint-specific byte loops can usually use ByteChunks, Lines, or io.copy.

v0.50.0 does not add filesystem watchers, memory mapping, advisory locking, public threads, parallel iterators, asynchronous closure bodies, generator declarations, shell parsing, implicit executable search, or targets other than arm64-darwin.

Release Qualification

Release-content commit b3bfaff4e36882c3616d2aa84ccddedf694ea62d passed the complete disposable compiler gate. Two independent optimized builds produced byte-identical archives and recursively identical installed homes. The retained archive is 9,095,913 bytes with SHA-256 2a7c60f42f055c682c1a18e2600ec898e17c1e7ed2ca7e2aa91025ac6a0af4c0 and contains exactly 307 standard-library files. A fresh extraction passed version and installation diagnosis, locked/offline package workflows, native build and execution, every public example, the complete asynchronous file-report success and cleanup contracts, framed LSP analysis, immutability checks, and compiler and standard-library tamper rejection. The published release reused that exact archive without rebuilding it.