Skip to content

Standard Library

Table of Contents

  1. Core Functions
  2. FilePath
  3. File
  4. URL
  5. CharacterSet
  6. Unicode
  7. String Trimming
  8. List
  9. Networking (TcpClient)
  10. HttpClient
  11. Crypto
  12. Process
  13. Subprocess
  14. Clock
  15. Range / OpenRange
  16. ArrayIterator
  17. Builtin Managed Types

Crypto

sha256

Compute the SHA-256 cryptographic hash of a byte array (FIPS 180-4).

export function sha256(data ByteArray) returns ByteArray

Parameters:

  • data — The input bytes to hash

Returns: A 32-byte ByteArray containing the SHA-256 digest

Example:

var data = ByteArray.create()
data.push(0x61)
data.push(0x62)
data.push(0x63)
let hash = sha256(data)
// hash contains the SHA-256 of "abc" (32 bytes)

Core Functions

I/O Functions

print(value String) // Print string to stdout

Math Functions

abs(x float) float // Absolute value (int auto-promoted to float)
sqrt(x float) float // Square root
floor(x float) float // Round toward negative infinity
ceil(x float) float // Round toward positive infinity
round(x float) float // Round to nearest (banker's rounding)
trunc(x float) int // Truncate toward zero
min(a float, b float) float // Minimum of two values
max(a float, b float) float // Maximum of two values
// Math library (stdlib) — called as Math.sin(x), Math.cos(x), etc.
Math.sin(x float) float // Sine (radians)
Math.cos(x float) float // Cosine (radians)
Math.tan(x float) float // Tangent (radians)
Math.atan(z float) float // Arc tangent
Math.atan2(y float, x float) float // Two-argument arc tangent
Math.exp(x float) float // e^x
Math.log(x float) float // Natural logarithm
Math.log2(x float) float // Base-2 logarithm
Math.log10(x float) float // Base-10 logarithm
Math.pow(base float, exponent float) float // Power
floor(x float) int // Round down
ceil(x float) int // Round up
round(x float) int // Round to nearest
trunc(x float) int // Truncate toward zero

Compile-Time Functions

sizeof(TypeName) int // Size of a type in bytes (compile-time constant)

sizeof accepts a type name and returns its storage size in bytes as a compile-time integer constant. No runtime cost. Primitive sizes: int (8), float (8), bool (1), byte (1). Struct types use 8 bytes per field (minimum 8). Enum types use 8 bytes. Ranged type aliases use the optimal storage width for their range.

Concurrency Functions

sleep(milliseconds int) // Suspend current green thread for given duration

Formatting Functions

format_int(value int) String // Format int as string
format_float(value float) String // Format float as string

FilePath

FilePath is a type-safe wrapper around String for filesystem paths. It normalizes path separators to the platform-native format on construction and provides methods for path manipulation.

Construction:

var p = FilePath from "C:\\Users\\test.txt" // From string literal (panics on invalid chars)
var q = try FilePath.from("hello.maxon") otherwise ... // From string (throws FilePathError)
var r = FilePath from "file:///C:/Users/test.txt" // file:// URLs are converted to paths
var s = try FilePath.from("file:///home/user/f.txt") otherwise ... // Also works with from()

Both init() and from() transparently accept file:// URLs, parsing them with URL.parse() and extracting the filesystem path. On Windows, the leading / before drive letters is stripped (e.g. /C:/path becomes C:\path). Non-file URL schemes (e.g. https://) cause a panic in init() or throw FilePathError.notFileURL in from().

Component Extraction:

p.filename() // "test.txt"
p.fileExtension() // ".txt"
p.stem() // "test"
try p.parent() // FilePath("C:\\Users") — throws FilePathError.noParent if no parent

Path Manipulation:

p.join("docs") // Append component with platform separator
p.join(otherFilePath) // Join with another FilePath
p.changeExtension(".exe") // Replace file extension
p.normalize() // Returns self (normalized on construction)

Query Methods:

p.isEmpty() // true if path is empty string
p.isAbsolute() // true for drive paths (C:\) or UNC paths (\\server)
p.isRelative() // opposite of isAbsolute
p.isInside(dir) // true if p == dir or dir is a proper ancestor (component-aware,
// case-insensitive on Windows, exact on POSIX — matches equals())

Resolution:

p.resolve(base) // resolve relative path against base; absolute paths returned unchanged

Static Methods:

FilePath.separator() // Platform-native separator ("\" on Windows, "/" on Linux)

FilePath implements Equatable, Hashable, Stringable, and InitableFromStringLiteral. Equality and hashing follow host filesystem semantics: case-insensitive on Windows (NTFS treats C:\Foo and c:\foo as the same path), exact byte match on POSIX.

All File and Directory methods accept FilePath parameters:

let fp = FilePath from "data.txt"
let content = try File.readText(fp) otherwise ...
try File.writeText(fp, content: "hello")
let files = try Directory.list(FilePath from "./") otherwise ...

File

File provides static methods for reading, writing, deleting, and querying files. It is defined in stdlib/File.maxon. All methods accept FilePath parameters.

Type Aliases

export typealias FileSize = int(0 to u64.max) // File size in bytes
export typealias Timestamp = int(0 to u64.max) // Unix epoch seconds

FileInfo

Metadata about a file, returned by File.info(). All fields are obtained from a single OS call.

export type FileInfo
export let size as FileSize
export let modifiedTime as Timestamp
export let createdTime as Timestamp
export let accessedTime as Timestamp
export let isDirectory as bool
export let isReadOnly as bool
end 'FileInfo'
FieldTypeDescription
sizeFileSizeFile size in bytes
modifiedTimeTimestampLast modification time (Unix epoch seconds)
createdTimeTimestampCreation time (Unix epoch seconds)
accessedTimeTimestampLast access time (Unix epoch seconds)
isDirectorybooltrue if the path is a directory
isReadOnlybooltrue if the file is read-only

FilePermission (enum)

CaseDescription
normalStandard file permissions (0666)
executableExecutable permissions (0755, Unix)

Error Types

export enum FileReadError implements Error
notFound // file not found when reading
end 'FileReadError'
export enum FileWriteError implements Error
failed // write operation failed
end 'FileWriteError'
export enum FileDeleteError implements Error
notFound // file not found when deleting
end 'FileDeleteError'
export enum FileInfoError implements Error
notFound // file not found when querying metadata
end 'FileInfoError'

API Summary

MethodReturnsThrowsDescription
File.readText(path FilePath)StringFileReadErrorRead file as UTF-8 string
File.readBinary(path FilePath)ByteArrayFileReadErrorRead file as raw bytes
File.writeText(path FilePath, content String, mode FilePermission = .normal)FileWriteErrorWrite string to file
File.writeBinary(path FilePath, content ByteArray, mode FilePermission = .normal)FileWriteErrorWrite bytes to file
File.exists(path FilePath)boolCheck if file exists
File.delete(path FilePath)FileDeleteErrorDelete a file
File.info(path FilePath)FileInfoFileInfoErrorGet file metadata

File.info

export static function info(path FilePath) returns FileInfo throws FileInfoError

Parameters:

  • path — The path to query

Returns: A FileInfo struct containing the file’s size, timestamps, and attributes

Throws: FileInfoError.notFound when the file does not exist

Example:

let fp = FilePath from "data.txt"
let info = try File.info(fp) otherwise 'err'
print("file not found")
return 1
end 'err'
print("size: {info.size}")
print("modified: {info.modifiedTime}")
print("is directory: {info.isDirectory}")

URL

URL provides RFC 3986 compliant URI parsing, serialization, and reference resolution. It is defined in stdlib/URL.maxon.

Parsing:

var url = try URL.parse("https://example.com:8080/path?q=1#top") otherwise 'err'
// handle error
end 'err'

Always-available accessors:

url.scheme() // "https" (empty string for relative references)
url.path() // "/path" (always present, may be empty)

Throwing accessors (throw URLError.fieldNotPresent if not set):

var host = try url.host() otherwise "default" // "example.com"
var port = try url.port() otherwise 443 // 8080
var ui = try url.userinfo() otherwise "" // userinfo before @
var query = try url.query() otherwise "" // "q=1"
var frag = try url.fragment() otherwise "" // "top"

Serialization:

url.toString() // "https://example.com:8080/path?q=1#top"

Reference Resolution (RFC 3986 Section 5):

var base = try URL.parse("http://a/b/c/d?q") otherwise ...
var resolved = try URL.resolve(base, reference: "../g") otherwise ...
resolved.toString() // "http://a/b/g"

Error Types:

ErrorDescription
URLError.emptyInputInput is empty or whitespace-only
URLError.invalidSchemeScheme starts with non-alpha or contains invalid characters
URLError.invalidHostMalformed host (e.g., unclosed IPv6 bracket)
URLError.invalidPortPort is non-numeric or exceeds 65535
URLError.invalidEncodingMalformed percent-encoding (e.g., %GG, %2)
URLError.relativeWithoutBaseresolve() called with a base URL that has no scheme
URLError.fieldNotPresentAccessor called for a component not present in the URL

URL implements Equatable and Stringable.


CharacterSet

CharacterSet represents a set of characters for use with string trimming and character classification. It is defined in stdlib/CharacterSet.maxon.

Static Factory Methods

Create a CharacterSet using one of the built-in factory methods:

var ws = CharacterSet.whitespacesAndNewlines() // All Unicode whitespace including newlines
var spaces = CharacterSet.whitespaces() // Spaces and tabs only (no newlines)
var nl = CharacterSet.newlines() // Newline characters only (LF, CR, CRLF, etc.)
var digits = CharacterSet.decimalDigits() // Unicode decimal digits (Nd category)
var letters = CharacterSet.letters() // Unicode letters and marks (L*, M* categories)
var alnum = CharacterSet.alphanumerics() // Unicode letters, marks, and numbers
var punct = CharacterSet.punctuation() // Unicode punctuation (P* categories)
var custom = CharacterSet.from(CharSet from ['a', 'e', 'i', 'o', 'u']) // Custom set

Instance Methods

ws.contains('A') // false
ws.contains(' ') // true
MethodReturnsDescription
contains(c Character)boolCheck if the character is in the set

Unicode

Unicode provides Unicode character classification utilities. It is defined in stdlib/Unicode.maxon.

Static Methods

Unicode.isWhitespace(32) // true (space)
Unicode.isWhitespace(65) // false ('A')
MethodReturnsDescription
isWhitespace(cp Codepoint)boolCheck if a codepoint is Unicode whitespace

String Trimming

The String type provides methods for removing characters from the start and end of a string. Each method has two forms: one that accepts a CharacterSet parameter, and a convenience overload that trims whitespace by default.

Trimming with CharacterSet

"123hello456".trim(CharacterSet.decimalDigits()) // "hello"
"...hello!!!".trim(CharacterSet.punctuation()) // "hello"
"xxxhelloxxx".trimStart(CharacterSet.from(CharSet from ['x'])) // "helloxxx"
"xxxhelloxxx".trimEnd(CharacterSet.from(CharSet from ['x'])) // "xxxhello"

Trimming Whitespace (convenience)

" hello ".trim() // "hello"
" hello ".trimStart() // "hello "
" hello ".trimEnd() // " hello"
MethodReturnsDescription
trim(in CharacterSet)StringRemove matching characters from both ends
trimStart(in CharacterSet)StringRemove matching characters from the start
trimEnd(in CharacterSet)StringRemove matching characters from the end
trim()StringRemove whitespace from both ends
trimStart()StringRemove whitespace from the start
trimEnd()StringRemove whitespace from the end

The no-argument convenience methods are equivalent to calling the CharacterSet variants with CharacterSet.whitespacesAndNewlines().


Search for substrings within a string. Returns a StringIndex with both the character position and byte offset.

var s = "hello world hello"
var first = try s.findFirst("hello") otherwise s.endIndex()
print("{first.charIndex()}\n") // 0
var last = try s.findLast("hello") otherwise s.endIndex()
print("{last.charIndex()}\n") // 12
MethodReturnsDescription
findFirst(needle String)StringIndex throws StringErrorFind first occurrence of needle
findLast(needle String)StringIndex throws StringErrorFind last occurrence of needle
contains(needle String)boolCheck if string contains substring
contains(character Character)boolCheck if string contains character
startsWith(prefix String)boolCheck if string starts with prefix
endsWith(suffix String)boolCheck if string ends with suffix

String Indexing and Slicing

StringIndex carries both a grapheme-cluster index and a byte position, so stepping is O(1) without re-scanning UTF-8. Use startIndex() / endIndex() to obtain the endpoints, indexAfter / indexBefore to step, and charAt / slice to read.

var s = "héllo"
var idx = s.startIndex()
let first = s.charAt(idx) // 'h'
idx = try s.indexAfter(idx) otherwise s.endIndex()
let second = s.charAt(idx) // 'é'
// Walk backward from the end:
var i = s.endIndex()
while i != s.startIndex() 'rev'
i = try s.indexBefore(i) otherwise break
print("{s.charAt(i)}\n")
end 'rev'
// Slice between two indices:
let head = s.slice(s.startIndex(), endIndex: idx) // "hé"
MethodReturnsDescription
startIndex()StringIndexIndex of the first grapheme cluster
endIndex()StringIndexOne-past-the-end index
charAt(idx StringIndex)CharacterGrapheme cluster at idx
indexAfter(idx StringIndex)StringIndex throws StringErrorNext grapheme boundary. Throws at endIndex().
indexBefore(idx StringIndex)StringIndex throws StringErrorPrevious grapheme boundary. Throws at startIndex().
slice(start StringIndex, endIndex StringIndex)StringSubstring [start, endIndex)
slice(start StringIndex, length GraphemeCount)StringSubstring starting at start, length graphemes long

StringIndex.charIndex() returns the grapheme-cluster index; StringIndex.bytePos() returns the UTF-8 byte offset. Both are O(1) accessors.


String Properties

var s = "hello"
print("{s.count()}\n") // 5 (grapheme cluster count)
print("{s.byteLength()}\n") // 5 (UTF-8 byte count)
print("{s.isEmpty()}\n") // false
print("{s.isAscii()}\n") // true
MethodReturnsDescription
count()GraphemeCountNumber of user-perceived characters (grapheme clusters). Recomputed each call — O(n) in byte length; callers that need the count repeatedly should cache it.
byteLength()ByteCountNumber of UTF-8 bytes
isEmpty()boolTrue if the string has no content
isAscii()boolTrue if all bytes are in the ASCII range (< 128). Enables optimized code paths.
cstr()cstringNUL-terminated UTF-8 pointer view of the string. Use when passing the string to a __Builtins.* runtime intrinsic whose parameter is declared cstring. Copies the buffer only when buffer[length] != 0 (i.e. when the underlying allocation is packed tight against capacity), so the returned pointer is always safely NUL-terminated.

String Append

String.append grows a string’s buffer in place, avoiding the allocation of a new string.

var s = "Hello"
s.append(" World") // s is now "Hello World"
MethodDescription
append(other String)Append another string’s content in place

List

List is a generic doubly linked list backed by __ManagedList (a builtin compiler-synthesized type, like Array and String) for efficient node management with automatic memory cleanup. It provides O(1) insertion and removal at both ends, and O(n) indexed access.

Creating a List

Create a concrete List type with typealias, then initialize with {}:

typealias Integer = int(i64.min to i64.max)
typealias IntList = List with Integer
var list = IntList.create() // Empty list

Adding Elements

list.prepend(1) // Add to front — O(1)
list.append(2) // Add to back — O(1)
try list.insert(1, value: 99) otherwise ignore // Insert at index [0, count] — O(n), throws ArrayError if at > count

Accessing Elements

var first = try list.first() otherwise 0 // First element (throws ArrayError)
var last = try list.last() otherwise 0 // Last element (throws ArrayError)
var elem = try list.get(1) otherwise 0 // Element at index (throws ArrayError)

Removing Elements

var removed = try list.removeFirst() otherwise 0 // Remove front — O(1)
var popped = try list.removeLast() otherwise 0 // Remove back — O(1)
var at2 = try list.remove(at: 2) otherwise 0 // Remove at index — O(n)
list.clear() // Remove all elements

Query

list.count() // Number of elements
list.isEmpty() // true if empty

Iteration

List implements Iterable, so it supports for-in loops:

for item in list 'loop'
print("{item}")
end 'loop'

Complexity Summary

OperationTime
prependO(1)
removeFirstO(1)
appendO(1)
removeLastO(1)
get, insert, remove(at:)O(n)
first, last, count, isEmptyO(1)
iteration (for-in)O(n) total

Networking (TcpClient)

TcpClient provides TCP client networking with automatic resource cleanup. It is defined in stdlib/TcpClient.maxon. The socket is backed by __ManagedSocket, a builtin type whose destructor closes the file descriptor when the last reference goes out of scope.

NetworkPort Alias

The NetworkPort type alias constrains port numbers to the valid TCP range:

typealias NetworkPort = int(1 to 65535)

NetworkError

All networking operations throw NetworkError, an enum conforming to Error:

enum NetworkError implements Error
resolveFailed // DNS lookup failed
connectFailed // TCP connection refused or timed out
sendFailed // OS-level send error
recvFailed // OS-level recv error
connectionClosed // peer closed the connection
end 'NetworkError'

Connecting

TcpClient.connect resolves the hostname, creates a TCP socket, and connects:

let client = try TcpClient.connect("example.com", port: 4242)

Sending Data

send transmits all bytes of a string, looping internally to handle partial sends. It returns the total number of bytes sent:

let bytesSent = try client.send("Hello\n")

Receiving Data

recv reads up to bufferSize bytes from the connection and returns them as a String:

let response = try client.recv(1024)

Closing

close is idempotent and safe to call multiple times. The socket also closes automatically when the TcpClient goes out of scope:

client.close()

API Summary

MethodReturnsThrowsDescription
TcpClient.connect(host String, port NetworkPort)TcpClientNetworkErrorConnect to a TCP server
send(data String)ByteCountNetworkErrorSend all bytes of a string
recv(bufferSize ByteCount)StringNetworkErrorReceive up to bufferSize bytes
close()Close the connection (idempotent)

Example: Simple TCP Client

function main() returns ExitCode
let client = try TcpClient.connect("localhost", port: 8080) otherwise 'err'
print("connection failed")
return 1
end 'err'
_ = try client.send("GET / HTTP/1.0\r\n\r\n") otherwise 'err'
print("send failed")
return 1
end 'err'
let response = try client.recv(4096) otherwise 'err'
print("recv failed")
return 1
end 'err'
print(response)
client.close()
return 0
end 'main'

HttpClient

HTTP/1.1 client for making HTTP requests over TCP connections. HTTP only (no HTTPS/TLS). Uses Connection: close for simple response reading.

HttpError (enum, implements Error)

VariantDescription
invalidUrlURL could not be parsed
connectFailedTCP connection failed
sendFailedSending the request failed
recvFailedReceiving the response failed
invalidResponseResponse could not be parsed

HttpMethod (enum)

Variant
get
post
put
delete
head
patch

StatusCode (enum)

VariantValue
ok200
created201
noContent204
movedPermanently301
found302
notModified304
badRequest400
unauthorized401
forbidden403
notFound404
methodNotAllowed405
conflict409
gone410
internalServerError500
notImplemented501
badGateway502
serviceUnavailable503

HttpHeaders

Case-insensitive HTTP header map. Header names are lowercased on storage.

MethodSignatureDescription
createstatic function create() returns HttpHeadersCreate an empty header map
setfunction set(name String, value String)Set a header
getfunction get(name String) returns String throws HttpErrorGet a header value
hasfunction has(name String) returns boolCheck if a header exists

HttpRequest

MethodSignatureDescription
createstatic function create(method HttpMethod, url String) returns HttpRequest throws HttpErrorCreate a request
setHeaderfunction setHeader(name String, value String)Set a request header
setBodyfunction setBody(body String)Set the request body
urlfunction url() returns URLGet the request URL
methodfunction method() returns HttpMethodGet the request method
headersfunction headers() returns HttpHeadersGet the request headers
bodyfunction body() returns StringGet the request body

HttpResponse

MethodSignatureDescription
statusCodefunction statusCode() returns StatusCodeGet the status code
reasonfunction reason() returns StringGet the reason phrase
headersfunction headers() returns HttpHeadersGet the response headers
bodyfunction body() returns StringGet the response body
headerfunction header(name String) returns String throws HttpErrorGet a response header by name

HttpClient

Stateless HTTP/1.1 client. All methods are static.

MethodSignatureDescription
sendstatic function send(request HttpRequest) returns HttpResponse throws HttpErrorSend an HTTP request
getstatic function get(url String) returns HttpResponse throws HttpErrorPerform a GET request
poststatic function post(url String, body String) returns HttpResponse throws HttpErrorPerform a POST request
putstatic function put(url String, body String) returns HttpResponse throws HttpErrorPerform a PUT request
deletestatic function delete(url String) returns HttpResponse throws HttpErrorPerform a DELETE request

Example: Simple GET

function fetchData() returns ExitCode throws HttpError
let response = try HttpClient.get("http://httpbin.org/get")
print(response.body())
return 0
end 'fetchData'

Example: POST with body

function postData() returns ExitCode throws HttpError
var request = try HttpRequest.create(HttpMethod.post, url: "http://httpbin.org/post")
request.setHeader("content-type", value: "application/json")
request.setBody("{\"key\": \"value\"}")
let response = try HttpClient.send(request)
print(response.statusCode())
return 0
end 'postData'

Limitations:

  • HTTP only (no HTTPS/TLS)
  • No chunked transfer encoding — uses Connection: close
  • No redirect following (returns 3xx as-is)
  • No streaming — entire response buffered in memory

Process

Process exposes introspection of the currently-running process. For launching child processes, see Subprocess; for monotonic time, see Clock.

Exit codes: Process.ExitCode is a platform-narrowed alias that ranges over 0 .. u32.max on Windows and 0 .. 255 on every non-Windows target (Linux, macOS, WASI), matching the POSIX byte-sized exit-code convention that portable programs target. Use it as the return type of main.

function main() returns ExitCode
return 0
end 'main'

Static Methods:

MethodReturnsThrowsDescription
executablePath()FilePathProcessIntrospectionErrorAbsolute path to the running executable. Uses GetModuleFileNameA (Windows), _NSGetExecutablePath (macOS), /proc/self/exe (Linux). Throws pathUnavailable when the OS lookup fails.

Errors:

enum ProcessIntrospectionError implements Error
pathUnavailable
end 'ProcessIntrospectionError'

Example:

let exe = try Process.executablePath() otherwise return 2
print("Running as: {exe.path}\n")

Subprocess

Launch and manage child processes. Modeled after Swift’s Subprocess (swift-foundation SF-0007). The hot path is Subprocess.run(.name("git"), arguments: argv), which captures stdout/stderr into a CollectedOutput value. For full control, build a Configuration and call .run() on it.

Not available on wasm32-wasi — WASI has no process-spawn primitives. Wrap callers in #if not os(Wasi) for portable stdlib code.

Hot path

var argv = StringArray.create()
argv.push("status")
let result = try Subprocess.run(Executable.name("git"), arguments: argv) otherwise return 1
if result.succeeded() 'ok'
print(result.stdout)
end 'ok'

Executable

union Executable
name(value String) // Bare name; resolved via PATH (and PATHEXT on Windows)
path(value FilePath) // Explicit path; used verbatim
end 'Executable'
MethodReturnsThrowsDescription
resolve()FilePathExecutableErrorConcrete launchable path. .path(p) returns p; .name(n) performs a PATH lookup.
displayName()StringHuman-readable form for diagnostics.

Errors: ExecutableError.notFound.

Subprocess — top-level entry

MethodReturnsThrowsDescription
run(executable, arguments)CollectedOutputSubprocessErrorRun with default options (inherit cwd, inherit env, no stdin, collect stdout/stderr up to 16 MiB, no timeout).
run(executable, arguments, workingDirectory)CollectedOutputSubprocessErrorSame as above with explicit cwd.
run(executable, arguments, workingDirectory, timeoutMs)CollectedOutputSubprocessErrorSame as above with a kill-after deadline. timeoutMs = 0 means “wait forever”.

All overloads route through Configuration.run(). From an async context (async Subprocess.run(...)) the spawn yields the parent green thread to the scheduler so siblings make progress while the child runs.

Configuration — full control

type Configuration
export var executable as Executable
export var arguments as StringArray
export var workingDirectory as FilePath // Empty path means "inherit"
export var environment as Environment
export var standardInput as InputSource
export var standardOutput as OutputDestination
export var standardError as OutputDestination
export var timeoutMs as DurationMs // 0 means "wait forever"
export var platformOptions as PlatformOptions
end 'Configuration'
MethodReturnsThrowsDescription
Configuration.create(executable)ConfigurationBuild a Configuration with sensible defaults (see comments above).
run()CollectedOutputSubprocessErrorRun the configured subprocess and collect its output.
runDetached()PidSubprocessErrorSpawn detached from the parent and return the pid. stdin/stdout/stderr are forced to discard.

Environment

union Environment
inherit // Child sees the parent's env unchanged
inheritUpdating(overrides Map with String, String) // Inherit + overwrite specific keys
custom(vars Map with String, String) // Child sees exactly these vars
end 'Environment'

InputSource / OutputDestination

union InputSource
none // stdin closed immediately
inherit // Pass through parent's stdin
bytes(data String) // Write `data` to stdin, then close
file(path FilePath) // Read stdin from a file
end 'InputSource'
union OutputDestination
discard // Output dropped
inherit // Pass through to parent's stream
collect(limitBytes ByteLimit) // Read into CollectedOutput, truncated at limitBytes
file(path FilePath) // Redirect to a file
end 'OutputDestination'

CollectedOutput

type CollectedOutput
export var status as TerminationStatus
export var stdout as String
export var stderr as String
export var pid as Pid
export var durationMs as DurationMs
end 'CollectedOutput'
MethodReturnsDescription
succeeded()booltrue iff status.isSuccess() (exited cleanly with code 0).
exitCode()ExitIntRaw integer status code.

TerminationStatus

union TerminationStatus
exited(code ExitInt) // Child called exit(code)
signalled(code ExitInt) // Unix: killed by signal. Windows: NTSTATUS abnormal exit.
end 'TerminationStatus'
MethodReturnsDescription
isSuccess()booltrue iff exited(0).
code()ExitIntThe raw integer code, regardless of termination kind.

PlatformOptions

type PlatformOptions
export var windowsHideWindow as bool
export var windowsCreateNewProcessGroup as bool
end 'PlatformOptions'
Static methodReturnsDescription
defaults()PlatformOptionsAll flags false.

Errors

union SubprocessError implements Error
executableNotFound(name String)
spawnFailed(reason String)
ioFailed(reason String)
timeout(elapsedMs DurationMs)
inputTooLarge
end 'SubprocessError'
MethodReturnsDescription
displayReason()StringSingle-line description for diagnostics.

Async use

let p = async Subprocess.run(exe, arguments: argv)
let r = try await p otherwise return 1

The same Subprocess.run is callable from sync and async contexts. From a green thread, the wait yields to the scheduler; from a plain call, it blocks the OS thread.

StreamingSubprocess — long-lived child with caller-driven stdio

Use when the parent needs interactive request/response with a long-lived child — e.g. a worker pool that handles many jobs over its lifetime. Unlike Subprocess.run(...) (which fires the process, drains both output streams via background threads, and returns a CollectedOutput when the child exits), StreamingSubprocess keeps the pipes open and exposes per-line operations.

Currently Windows-only (the runtime drives FILE_FLAG_OVERLAPPED named pipes through IOCP).

let child = try StreamingSubprocess.spawn(Executable.path(p), arguments: argv)
try child.writeStdinLine("JOB:1")
let line = try child.readStdoutLine()
child.closeStdin()
let code = try child.wait()
child.release()
MethodReturnsThrowsDescription
spawn(executable, arguments)StreamingSubprocessSubprocessErrorSpawn with stdin/stdout/stderr as pipes the caller drives. Inherits parent’s cwd.
spawnWithCwd(executable, arguments, workingDirectory)StreamingSubprocessSubprocessErrorSame as spawn with an explicit working directory.
writeStdinLine(line)SubprocessErrorWrite line + "\n" to the child’s stdin. Throws on broken pipe.
readStdoutLine()StringSubprocessErrorRead one line; returns "" on EOF. Strips trailing CRLF / LF.
readStdoutLineCapped(maxBytes)StringSubprocessErrorSame with an explicit per-line truncation cap.
readStderrLine()StringSubprocessErrorStderr-side companion to readStdoutLine.
readStderrLineCapped(maxBytes)StringSubprocessErrorSame with an explicit cap.
closeStdin()Close the parent’s write end so the child sees EOF on stdin. Idempotent.
wait()ExitIntSubprocessErrorBlock until the child exits, return its exit code.
waitWithTimeout(timeoutMs)ExitIntSubprocessErrorSame with a deadline; throws timeout if it elapses (child is terminated).
release()Free the OS handle. Idempotent. Treat like close() on a file.

Forgetting release() leaks the handle and an OS process slot. Lines longer than the per-call cap are truncated; the remainder is delivered on the next call. Default cap is 1 MiB.


Clock

Monotonic time helpers. Use for measuring elapsed durations — absolute values are platform-defined (e.g. milliseconds since boot) and only meaningful when subtracted.

Type aliases:

  • Clock.InstantMs = int(0 to u64.max) — an absolute reading from the monotonic clock.
  • Clock.DurationMs = int(0 to u64.max) — a duration in milliseconds.

Static Methods:

MethodReturnsDescription
nowMs()InstantMsMonotonic time in milliseconds. Differences between two readings are meaningful; the absolute value is not.
elapsedMs(since: instant)DurationMsMilliseconds elapsed since a prior nowMs() reading. Clamps to 0 if the clock moves backwards.

Example:

let start = Clock.nowMs()
doWork()
let elapsed = Clock.elapsedMs(since: start)
print("Took {elapsed}ms\n")

Backed by QueryPerformanceCounter (Windows), clock_gettime(CLOCK_MONOTONIC) (POSIX), or the WASI monotonic-clock interface.


Range / OpenRange

Outside a for-in header, an integer range expression evaluates to a value:

ExpressionTypeIteration
start to endRangeInclusive — visits both endpoints
start upto endOpenRangeHalf-open — excludes end

Both implement Iterable with (RangeBound, RangeIterator). RangeBound is an alias for the full int range (int(i64.min to i64.max)).

let r = 1 upto 5 // OpenRange value
for x in r 'loop' ... end 'loop' // 1, 2, 3, 4
let it = try (1 to 4).createIterator() otherwise return 0
for v in it 'loop' ... end 'loop' // 1, 2, 3, 4
for (iter, v) in (10 upto 13).withIterator() 'loop'
print("{iter.index()}:{v}\n") // 0:10 1:11 2:12
end 'loop'

createIterator() throws IterationError.exhausted for an empty range (finish < start for Range, endExclusive <= start for OpenRange).

The for i in start to end form inside a loop header still desugars to a counted while-loop with no allocation — using to/upto in expression position is what triggers the constructor calls.

RangeIterator implements Iterator with RangeBound, BidirectionalIterator, providing current(), index(), advance(), and retreat().


ArrayIterator

ArrayIterator implements BidirectionalIterator with Element and provides cursor-style random access into an Array. The iterator always points at a valid element; navigation methods throw IterationError if they would move out of bounds, while current() is unchecked because the position is always valid.

Declaration

typealias MyIter = ArrayIterator with MyElement

Creating an Iterator / Cursor

var arr = [10, 20, 30]
var c = try arr.cursor() otherwise panic("empty array")

cursor() (alias of createIterator()) throws IterationError.exhausted if the array is empty.

Methods

MethodReturnsThrowsDescription
current()ElementElement at the current position (no bounds check)
index()iterator-defined index aliasCurrent position index (e.g. ArrayIterator returns ElementIndex)
advance()IterationErrorMove forward by 1. Throws .exhausted at end.
advanceBy(n IterStep)IterationErrorMove forward by n (from Iterator extension). Throws .exhausted if out of bounds.
retreat()IterationErrorMove backward by 1. Throws .atStart at position 0.
retreatBy(n IterStep)IterationErrorMove backward by n (from BidirectionalIterator extension). Throws .atStart if out of bounds.
peek(ahead ElementCount)ElementIterationErrorRead element at position + ahead. Throws .exhausted if out of bounds.

advanceBy and retreatBy are supplied as default extension methods on Iterator / BidirectionalIterator; they repeatedly call advance / retreat, so a partial move leaves the iterator at the point where the throw occurred.

IterationError (enum, implements Error)

CaseDescription
exhaustedIterator would move past the last element
atStartIterator would move before position 0

Example

typealias IntIter = ArrayIterator with int
var arr = [1, 2, 3, 4, 5]
var c = try arr.cursor() otherwise panic("empty")
print("{c.current()}\n") // 1
try c.advance()
print("{c.current()}\n") // 2
let ahead = try c.peek(2) otherwise 0
print("{ahead}\n") // 4

Builtin Managed Types

The compiler provides several builtin managed types that wrap OS-level resources (file handles, sockets, directory search handles). These types use RAII via destructors: when the last reference to a managed object goes out of scope, the compiler automatically calls the destructor to release the underlying OS resource.

Managed types are not used directly by application code. Instead, stdlib wrapper types (File, Directory, TcpClient) provide the public API. The managed types are documented here for completeness and for stdlib authors.

__ManagedSocket

Wraps an OS socket file descriptor. Used internally by TcpClient. See Networking (TcpClient) for details.

Static Methods:

MethodReturnsThrowsDescription
tcpConnect(managed, port)__ManagedSocket__ManagedSocketErrorResolve hostname and connect a TCP socket. Throws resolveFailed when DNS fails, connectFailed when the connection is refused.

Instance Methods:

MethodReturnsThrowsDescription
sendFrom(managed, offset, length)int__ManagedSocketErrorSend length bytes from the managed buffer at offset. Throws bufferOutOfBounds if offset + length > capacity, sendFailed on OS error.
recv(managed)int__ManagedSocketErrorReceive up to managed.capacity bytes. Returns 0 when the peer closed gracefully. Throws recvFailed on OS error.
close()Close the socket handle. Idempotent; also called automatically by the destructor.

__ManagedFile

Wraps an OS file handle (Windows HANDLE or Linux file descriptor). Used internally by File.

Static Methods:

MethodReturnsDescription
openRead(managed)__ManagedFileOpen a file for reading. Returns -1 on failure.
openWrite(managed)__ManagedFileOpen a file for writing (creates or truncates). Returns -1 on failure.
exists(managed)intCheck if a file exists. Returns nonzero if the file exists.
delete(managed)intDelete a file. Returns 0 on success.

Instance Methods:

MethodReturnsDescription
size()intGet the file size in bytes.
read(managed, size)intRead up to size bytes into the managed buffer. Returns bytes read.
write(managed)intWrite the contents of the managed buffer. Returns bytes written, or negative on error.
close()Close the file handle. Idempotent; also called automatically by the destructor.

The managed parameters refer to __ManagedMemory buffers (the internal backing store of String and ByteArray).

__ManagedDirectory

Wraps an OS directory search handle (Windows FindFirstFile/FindNextFile or Linux opendir/readdir). Used internally by Directory.

Static Methods:

MethodReturnsThrowsDescription
openSearch(managed)__ManagedDirectory__ManagedDirectoryErrorOpen a directory search with a glob pattern. Throws openSearchFailed if the path does not exist or access is denied.
exists(managed)boolCheck if a path exists and is a directory.
create(managed)__ManagedDirectoryErrorCreate a directory. Throws createFailed on failure.
currentPath()__ManagedMemory__ManagedDirectoryErrorGet the current working directory as a managed string. Throws currentPathFailed on OS failure.

Instance Methods:

MethodReturnsThrowsDescription
filename()__ManagedMemoryGet the filename of the current search result. Panics on a closed iterator.
next()int__ManagedDirectoryErrorAdvance to the next search result. Returns non-zero if found, 0 when no more entries. Throws nextFailed on OS error.
close()Close the search handle. Idempotent; also called automatically by the destructor.

__ManagedMemoryCursor

Provides a cursor into a __ManagedMemory buffer. Increfs the source on creation; decrefs on destruction. Used internally by ArrayIterator.

Instance Methods:

MethodReturnsThrowsDescription
current()ElementLoad element at current position (no bounds check).
index()intRead the current position index.
advance()CursorErrorMove forward by 1 position.
retreat()CursorErrorMove backward by 1 position.
seek(index)CursorErrorJump to index. Throws when out of bounds.
peek(ahead)ElementCursorErrorRead element at position + ahead.