The Aether programming language
A compiled systems language built on actors.
Message-passing concurrency with type inference and pattern matching, compiled to native binaries. No VM, no garbage collector, nothing between your code and the machine.
curl -fsSL https://aether-lang.dev/install.sh | sh
Needs only a C compiler. Or grab a prebuilt binary.
message Inc { n: int } actor Counter { state count = 0 receive { Inc(n) -> { count = count + n println("count = ${count}") } } } main() { c = spawn(Counter()) c ! Inc { n: 41 } c ! Inc { n: 1 } }
Message-passing actors on a work-stealing, NUMA-aware scheduler across every core. Explicit (value, err) error handling. Compile-time contracts. Capability discipline in the language. A production HTTP stack in the standard library. All of it lowered to C you can read.
You can read what it compiles to.
Aether lowers to C a normal compiler builds, then GCC or Clang produces the native binary. No bytecode, no black box, and the same source always compiles to byte-identical C.
Every abstraction, enums, optionals, distinct types, contracts, is zero-cost: it disappears into plain C with no vtables and no virtual dispatch.
main() { println("hello, aether") }
#include <stdio.h> /* ... aether runtime preamble ... */ int main(int argc, char** argv) { aether_args_init(argc, argv); { #line 2 "hello.ae" puts("hello, aether"); } return 0; }
Errors without exceptions
Fallible functions return T!, a (value, err) pair. Handle it inline with or, or propagate with !. No exceptions, no hidden control flow.
safe_divide(a: int, b: int) -> int! { if b == 0 { return 0, "division by zero" } return a / b } q = safe_divide(10, 0) or -1 // -> -1
Contracts the compiler checks
Attach requires / ensures to a function. A predicate the compiler can prove is elided; one it can prove false is a build error, folded at the call site.
divide(a: int, b: int) -> int requires b != 0 { return a / b } divide(10, 0) // rejected at compile time
Config that is code.
A trailing block runs in the caller's scope, so a library's setup surface reads like a config file, but it's real Aether: conditionals, loops, and environment lookups, with no YAML dialect and no macro system.
It's the "DSL with scope" pattern, built into the grammar rather than bolted on as macros.
serve { host("127.0.0.1") port(9990) if os_getenv("STAGE") == "prod" { host("0.0.0.0") } repo("alpha", "/srv/alpha") repo("beta", "/srv/beta") }
More than a language.
std.http: routing, TLS, HTTP/2, WebSocket, SSE, and a full reverse proxy with load balancing, health checks, and caching. Plus JSON, crypto, regex, and more.extern. Tuple returns bind struct-returning C APIs with zero glue. Or embed Aether in Python, Java, and Ruby with --emit=lib.ae build --target=aarch64-linux, via a bundled cross toolchain. No cross-gcc, no sysroot. Or target WebAssembly and run the same actor code on a cooperative scheduler.hide, seal, and effect tags give an auditable, compiler-enforced dependency surface, defense-in-depth for trusted plugins, config, and hosted scripts.defer, compiler-managed string ownership, swappable allocators, and built-in leak tracking.Start writing Aether.
curl -fsSL https://aether-lang.dev/install.sh | sh
$ ae init hello && cd hello && ae run