C+
Packages · View as Markdown
v0.0.27 is a macOS / AppKit release. That is the supported path. Other platforms are not recommended; wait for a later version.

stdlib

The standard library is a vendored package. Every module lives in vendor/stdlib/src/<name>.cplus and imports as "stdlib/<name>". You import the modules you use, not the whole library.

I/O

import "stdlib/io" as io;
io::print("no newline");
io::println("with newline");
io::eprintln("to stderr");

Backed by printf, buffered through stdio.

Result and Option

Both are generic. There is no ? propagation; match on the variant or use guard let.

import "stdlib/result" as result;
import "stdlib/option" as option;

let r: result::Result[i32, result::IoError] = result::io_ok::[i32](42);
let some_n: option::Option[i32] = option::some::[i32](7);

Fallible standard-library operations return their failure instead of trapping: a lookup is an Option[T], a value-or-typed-error is a Result[T, E], and a mutation is a Status (stdlib/status: Ok / OutOfMemory / OutOfBounds / InvalidInput / Shared). See Error handling.

Collections

stdlib/vec is a growable, ownership-safe vector that implements Drop, so its buffer frees on scope exit. Allocation sizing is overflow-checked, malloc/realloc are null-checked, and every read is bounds-checked: there are no silent out-of-bounds reads.

import "stdlib/vec" as vec;
import "stdlib/status" as status;

var v: vec::Vec[i32] = vec::with_capacity::[i32](16 as usize);
let _a: status::Status = v.append(1);
let _b: status::Status = v.append(2);
let n: usize = v.count();

let first: option::Option[i32] = v.at(0 as usize);       // bounds-checked
let p: option::Option[*i32]    = v.at_ptr(0 as usize);   // in place, no copy

Reading is split by element kind, and bounds safety is the default:

  • at(i) -> Option[T] — bounds-checked copy of a Copy element, None when out of range.
  • at_ptr(i) -> Option[*T] — reads a non-Copy element in place, by pointer.

Mutating methods return Status rather than trapping: append(value), append_slice(s), set(value, at: i). Plus count(), is_empty(), as_slice() -> T[].

stdlib/slice is checked sub-views over the same T[] buffer (no allocation). The free-fn spelling ships the semantics; the xs.sub(from:to:) method form waits on generic slice impls:

import "stdlib/slice" as slice;

let s: i32[] = v.as_slice();
let mid: option::Option[i32[]] = slice::sub::[i32](s, 1 as usize, 4 as usize);
let head: i32[] = slice::prefix::[i32](s, 2 as usize);

sub returns None on an invalid range (from > to, or to past the end). prefix / suffix / drop_first / drop_last clamp.

stdlib/flags is a Copy option-set over one u64 word. Mutators return a new set:

import "stdlib/flags" as flags;

const FONT: u64 = 1u64 << 0;
const SIZE: u64 = 1u64 << 1;

var dirty: flags::Flags = flags::of(FONT);
dirty = dirty.with(SIZE);
if dirty.contains(FONT) { }

Bit values come from const masks or a payload-free enum discriminant cast at the call site (Mode::Fast as u64). Verbs: contains / intersects / with / without / toggled, plus union_with / intersect_with / minus.

stdlib/hash_map is a generic HashMap[K, V] (open addressing, linear probing, 0.75 load-factor grow). K must be Hash + Eq; primitives and str work today:

import "stdlib/hash_map" as hash_map;

var m: hash_map::HashMap[str, i32] = hash_map::new::[str, i32]();
m.insert("hello", 42);
let present: bool = m.contains_key("hello");

stdlib/hash_set adds a generic HashSet[T]. For Text keys there are two purpose-built types: StringSet (stdlib/string_set), with set algebra (union_with / intersection / difference / is_subset), and StringMap (stdlib/string_map), a Text-keyed owning map with slot enumeration. A failed insert returns a Status rather than trapping.

Text — the owned string

stdlib/text is the owned, growable string, Text. It is a plain stdlib type (the compiler knows it only through one lang-item), so its whole API lives here and grows without touching the compiler. The borrowed view str stays a built-in; Text is what you reach for when you need to own and build up text.

import "stdlib/text" as text;
import "stdlib/status" as status;

var s: text::Text = text::from_str("hello");
let _a: status::Status = s.append(", world");
let n: usize = s.count();

The surface: from_str; append / appending (the latter returns a new Text); count / is_empty; reads live on the blessed str view (count, trim, slice, find, split, …) and a Text reaches them through the str coercion. split returns Vec[str] views of the same buffer. A borrowed Text coerces to a str view automatically wherever a str is expected, so no as_str call is needed. Text is Send + Sync, so it is a valid thread::spawn payload and works inside Arc[Text].

String interpolation and .to_text() both produce a Text. Naming that owned value — binding it as Text, returning it, storing it — requires import "stdlib/text" (E0613); borrowed views (str) need no import.

Files and networking

  • stdlib/fsopen_read, create, read_to_end. File implements Drop and closes on scope exit.
  • stdlib/net — TCP client and server (connect_tcp, listen_tcp, accept). IPv4, numeric IPs.
  • stdlib/env — environment variables (var_into) and argv access.

Ownership wrappers

  • stdlib/box — a single heap-allocated owned value. new is fallible (Option). unwrap() consumes it and returns the inner T. into_raw(take this) -> *u8 surrenders the heap slot without freeing; from_raw(raw) -> Box[T] reclaims a pointer into_raw returned. Reconstructing two boxes from one pointer is a bad-free.
  • stdlib/arc — atomic refcounted shared ownership; clone() increments atomically, the last reference frees.
  • stdlib/rc — the single-threaded, non-atomic version. Rc[T] is !Send and !Sync, so the compiler rejects passing one across threads (E0502). Use Arc[T] to share across threads.
  • Uniqueness: Rc / Arc expose is_unique(), try_unwrap() -> Option[T] (recovers the value when this is the sole reference), and a scoped with_mut(f: fn(ref T)) -> Status that mutates in place only when the reference is unique (otherwise Status::Shared). MutexGuard gains scoped with / with_mut.

Concurrency

  • stdlib/thread, stdlib/atomic — threads and atomics. spawn / spawn_with move data into a worker. thread::scope plus Scope::lend lends a parent local; Scope::drop joins every worker. See Threads.
  • stdlib/mutex — pthread-backed mutual exclusion, internally refcounted (it collapses Arc into itself, since C+ has no &T to make Arc[Mutex[T]] work).
  • stdlib/channel — typed message passing; handles clone for multi-producer / multi-consumer use.
  • stdlib/future, stdlib/executor, stdlib/reactor, stdlib/time — the async runtime.

Other modules

stdlib/slice and stdlib/flags (above), stdlib/str (the blessed impl str method set), stdlib/cow (clone-on-write string), stdlib/range (the 0..n for in type), stdlib/iterator, stdlib/date, stdlib/process, stdlib/pty, stdlib/bundle, and stdlib/marker (the compiler's Copy / Send / Sync markers, which you rarely touch directly).