Language Cheat Sheet
This document summarizes the key syntax and concepts from the Silk language in a condensed form. It is meant as a quick reference; detailed semantics live in the other docs/language/ files.
Notes#
This cheat sheet includes both:
- the full language design (where some features are still evolving), and
- the currently implemented compiler subset.
For the authoritative “current implementation notes”, prefer:
- implementation status, and
- any “notes sections inside the relevant concept documents.
In particular, features such as regions (beyond the current with + new
subset), concurrency runtime (scheduler/event loop), and
dependent types are not implemented end-to-end yet. Value constraints are
expressed via Formal Silk (#require / #assure, including #require on
struct declarations).
In Silk currently:
- Runtime
let/varbindings and compile-timeconstbindings must have an initializer (diagnostics,E2015). - Destructuring
letbindings from structs are supported: - positional:
let (id, name) = User{ ... }; - named + aliasing:
let { data as d, id as i } = Record{ ... }; - Array destructuring is supported:
- arrays/slices:
let [a, b] = xs; - Enum destructuring is supported:
- variants:
let Ok(v) = expr;,let Pair(a, b) = expr;,let E::Variant(x) = expr;(traps on non-matching variants) - Refutable
letbindings are supported: let <pattern> = <expr> else { ... };(theelseblock must be terminal)constinitializers must be compile-time evaluable (diagnostics,E2041); in the Supported forms this is restricted to scalar expressions and calls toconst fnfunctions (still no/or%), plus string literals /conststring aliases.- Monomorphized generics are supported for
struct/interface/impland applied types (Name(args...)): - const parameters/arguments and generic functions are still rejected (
E2016), - A small concurrency subset is implemented (
Task(T)/Promise(T)plusyield/await; see concurrency). - The builtin
map(K, V)type form is removed; usestd::map::{HashMap, TreeMap}instead (E2017). - Function expressions are implemented as first-class function values:
- non-capturing: inferred
pure—let add = fn (x: int, y: int) -> x + y; - capturing closures: may capture immutable scalar locals/parameters by value;
forming captures inside
purecode is rejected in the Supported forms.
Types (Surface Forms)#
- Booleans:
bool—true,false. - Integers:
u8,i8,u16,i16,u32,i32,u64,i64,u128,i128,int. - Floats:
f32,f64,f128. - Char:
char. - String:
string. - Time:
Instant,Duration. - Optional:
T?(sugar forOption(T)). - References:
&T. - Arrays / slices:
T[],T[N]. - Maps / dictionaries:
std::map::{HashMap, TreeMap}(standard library). - Function types:
fn(params) -> R(discipline modifiers apply to function declarations; function types are unmodified in the Supported forms). - Function expressions (non-capturing, inferred
pure): - expression body:
fn (x: int, y: int) -> x + y - block body:
fn (x: int, y: int) -> int { return x + y; } - block body
voidshorthand:fn (x: int, y: int) { ... }(implicitvoid) - capturing closures are supported as a subset; see types.
- Structs / enums / interfaces:
struct Name { ... },struct Name extends Base { ... }enum Name { ... }interface Name { ... },interface Name extends Base { ... }
Literals#
- Integers:
0,42, with base/suffixes as per the spec. - Floats:
3.14,1.0e-9. - Booleans:
true,false. - Chars:
'A', escape sequences. - Strings:
- single-line:
"hello", - multi-line: multi-line quoted forms.
- Durations: numeric + unit, e.g.
10ms,2s,5min. - Aggregates:
- arrays:
[1, 2, 3], - structs:
Point { x: 1, y: 2 }.
Operators#
- Arithmetic:
+,-,*,/,%. - Bitwise:
&,|,^,~,<<,>>. - Comparison:
==,!=,<,<=,>,>=. - Logical:
!,&&,||. - Assignment:
=,+=,-=,*=,/=. - Increment/decrement:
++,--(statement-likevoid). - Optional / nullability:
- optional chaining:
?., - coalescing:
??. - Member/scope:
.,::. - Ranges:
..,..=,.... - Other punctuation:
,,;,:,->,=>.
Operator precedence and associativity follow the rules in operators.
Flow Control#
if cond { ... } else { ... }(statement form)if let [mut] <pattern> = <expr> { ... } else { ... }(refutable pattern statement form; supportselse if let/else letchains and chained&& let [mut])let v = if cond { a } else { b };(ifexpression)loop { ... }(infinite loop; exits viabreak/return).while (cond) { ... }while let [mut] <pattern> = <expr> { ... }for pattern in iterable { ... }(ordinary binder form for ranges, builtin arrays/slices, and iterators).for let [mut] pattern in iterable { ... }(pattern-filtered iteration; matching elements run the body, non-matching elements are skipped).for (init; cond; step) { ... }(C-style loop header).async loop { ... }/task loop { ... }(loop forms in async context).match value { ... }— pattern matching.return expr;assert expr;orassert(expr, "message");break;continue;gpu (grid=<u64>, workspace=<u64>) { kernel(args...); }(checked, automatically synchronized GPU dispatch; returnsstd::gpu::DispatchResultin value position and is discardable in statement position; seegpu-launch-blocks.md).- Blocks:
{ stmt* }. - Expression statements:
expr;(where allowed).
See docs/language/flow-*.md for details.
Executable entrypoint (initial rule):
-
A minimal executable module defines exactly one top-level function:
fn main() -> int { return 0; } -
This
mainfunction takes no parameters and returnsint. The front-end enforces this shape for executable builds before code generation.
Optionals & Mutability#
- Declare optionals:
let x: T? = None;orlet x: Option(T) = None;. - Create values:
None,Some(value). - Use:
user.profile?.email— optional chaining.email ?? "default@example.com"— coalescing.
Mutability:
- Parameters and references are immutable by default.
- Grant mutation via
mut: - in function definition:
fn reset(mut r: &Runner) { ... }, - at call site (syntax per spec).
Structs, Impl Blocks, Interfaces#
-
Structs:
struct Frame { seq: u32, size: u16, flag: u8 } -
pure data, well-defined layout.
-
Impl blocks:
impl Frame { fn size_bits(self: &Frame) -> u32 { ... } } -
Interfaces:
interface Element { fn onclick(event: &Event) -> void; } impl Button as Element { fn onclick(self: &Button, event: &Event) -> void { ... } }
See structs-impls-layout.md and interfaces.md for details.
Regions & Buffers#
- Regions (fixed-size allocation context):
- declare:
const region region_buf: u8[1024]; - use:
with region_buf { let p: &Frame = new Frame{ ... }; } - anonymous:
with 1024 { let p: &Frame = new Frame{ ... }; } - Buffers:
- intrinsic
Buffer(T)with(ptr, capacity), - unsafe primitive underpinning higher-level collections.
- Allocation:
newuses the active region insidewith(seeregions.md).
Concurrency#
-
Function modifiers:
-
fn— normal. -
async fn—await-able; calling yieldsPromise(T). -
task fn— runs in parallel on a worker thread; calling yieldsTask(T). -
async task fn—async+task; calling yieldsPromise(Task(T)). -
Structured block:
```silk async fn get_dashboard_data() -> Dashboard { // Note: the scheduler-backed `async { ... }` semantics are still design work, // but the compiler implements `Task(T)`/`Promise(T)` handles, `yield`, and `await`. let mut user: User; let mut orders: Order[]; async { let user_promise = fetch_user_profile(123); let orders_promise = fetch_recent_orders(123); user = await user_promise; orders = await orders_promise; } return Dashboard(user, orders); } ```
To receive task values, use yield inside a task context (task { ... } or task fn):
task fn worker () -> int { return 42; }
async fn main () -> int {
let h = worker();
task {
let value: int = yield h;
return value;
}
}
See concurrency.md for deeper semantics.
Formal Silk#
#const— formal Silk declarations used inside specifications (not available at runtime).#require— preconditions.#assure— postconditions.#assert— block-local proof obligations.#invariant— invariants.#variant— termination measures.#monovariant— monotonic measures.theory/#theory— reusable proof obligations.
#require / #assure appear before functions; #invariant / #variant / #monovariant appear before loops; #const and #assert appear inside blocks. See formal-verification.md.
External Declarations & ABI (Quick View)#
-
Declare external bindings:
ext foo = fn (string) -> void; ext bar = u32; -
Strings:
-
Silk
stringis internally{ ptr, len }, -
C side uses
SilkString { char *ptr; int64_t len; }for embedding, -
extcalls to typical C APIs may passconst char *derived fromstringwhere appropriate.
See ext.md and abi libsilk for full details.
Source repository · Edit this page · View Markdown