Coming from Rust

The toolchain is written in Rust, so the debt is acknowledged. But Keal made the opposite memory trade: reference counting with a documented model instead of a borrow checker. You give up compile-time aliasing guarantees; you get a language with no lifetimes to write.

ConceptRustKeal
Bindinglet x = 1;val x = 1
Mutablelet mut x = 1;var x = 1
Structstruct P { x: f64 }record P(val x: Float)
OptionOption<String>String?
Unwrap or defaultopt.unwrap_or(d)opt ?: d
Matchmatch n { 0 => … }when (n) { 0 -> … }
Trait boundfn f<T: Ord>(x: T)func f<T: Ord>(x: T)
Closure|x| x * 2{ x -> x * 2 }
ResultResult<T, E> + ?try { } catch (e) { }
Rc / WeakRc<T> / Weak<T>the default / weak var f: T?
Threadsstd::thread::spawnsys.spawn({ self, msg -> … })

What will surprise you

No lifetimes, no borrow checker

Every heap value is counted, as if everything were Rc. Assignment shares; there is no move semantics to reason about, and nothing to annotate.

weak is the same idea you already know

A cycle is the one thing counting cannot free, and weak var is Weak<T> with the upgrade done for you: reading gives the target while it lives, null after.

Errors unwind rather than propagate

There is no ? operator and no Result: a failure throws, and catch binds the message. Integer overflow panics in release builds too.

Build a staticlib, declare the symbols with extern func, pass the .a to keal build.