Nocter v0.46.0 Release Notes
Nocter v0.46.0 completes UDP as a first-class asynchronous networking surface. One UdpSocket owner now supports immediate setup, executor-safe send and receive, explicit asynchronous deadlines, and clearly named blocking operations without exposing descriptor modes or creating a second async socket type.
This release intentionally renames the synchronous UDP transfer methods. No compatibility aliases are retained.
One Datagram Socket Owner
The same socket value is used in synchronous and asynchronous code:
var sender = UdpSocket.bind(sender_address)?
var receiver = UdpSocket.bind(receiver_address)?
await sender.send_to("ping".bytes(), receiver.local_address()?)?
let datagram = await receiver.receive(&+buffer)?
bind, numeric connect, local_address, and peer_address are immediate operations. They do not wait for external progress and do not return futures. A socket may use explicit destinations or be connected to one peer without changing its ownership representation.
Canonical Async and Explicit Blocking APIs
Asynchronous transfers own the base names:
sendandsend_totransmit one complete datagram;receivereturns one message boundary and its source address;_with_timeoutvariants use one explicit relative timeout;send_blocking,send_to_blocking, andreceive_blockingare the synchronous twins.
Configured socket read and write timeouts apply only to the blocking methods. Async timeouts are explicit inputs, become one fixed monotonic deadline before the first attempt, and are not restarted after interruption or readiness wakeup. A zero timeout still permits one immediate attempt.
Message Boundaries, Empty Datagrams, and Truncation
A successful send is atomic at the public boundary; partial datagram success is never reported. Receiving an empty datagram is a successful message rather than end-of-stream. If the caller's buffer is shorter than the message, DatagramRead reports the copied length, source address, and truncation while preserving the next datagram boundary.
Dropping a suspended transfer removes only its logical readiness wait. It does not close, duplicate, or consume the borrowed socket, and the same socket can be used by a later operation.
Closed Native Attempt Boundary
Generic syscall primitives remain conservatively blocking. v0.46.0 adds a finite set of closed datagram target operations for descriptor setup, bind, peer selection, connected and addressed send attempts, receive attempts, and address observation.
The runtime contract owns each operation's effect classification, target closure validates its exact standard declaration, and ARM64 lowering owns fixed Darwin syscall identities and flags. The private standard adapter owns native socket records. Standard source alone interprets immediate attempts as retry, readiness, timeout, truncation, and public errors. Later compiler layers do not infer an operation from a source path, function name, syscall number, or emitted instruction.
Editor and Integration Support
The public async-udp example demonstrates explicit-destination and connected loopback exchange. Native qualification covers IPv4 and IPv6, empty and truncated datagrams, readiness, timeout, cancellation, post-cancellation reuse, close, and normalized failure.
Formatting, hover, completion, signature help, contract and implementation navigation, semantic tokens, and inlay hints consume the same checked UDP contracts as compilation. No editor-only UDP model is present.
Migration and Non-goals
Existing synchronous UDP calls must move from send, send_to, and receive to the corresponding _blocking names. Async code uses the base names and awaits the returned future T! value.
v0.46.0 does not add multicast control, broadcast configuration, hostname-based datagram setup, batch datagram operations, ancillary messages, platform descriptor access, detached tasks, another future type, or another executor. The supported distribution remains a self-contained arm64-darwin compiler and standard library.
Release Qualification
Release-content commit ad30785c52479bd123c419887e081381051831c0 passed the complete compiler gate in a disposable target and two independent optimized package builds. The resulting archives and installed homes were identical. Fresh extraction passed the installed CLI, every public example, selected exact process contracts, native execution, framed LSP analysis, installed-home immutability, and compiler and standard-library tamper rejection.
The retained nocter-v0.46.0-arm64-darwin.tar.gz candidate is 8,943,469 bytes with SHA-256 2c5e4f300ac04cd112617a56b80e82d59dc514c3e037ceffc6b882acec091579. Publication reused this qualified archive without rebuilding it.