Coming from C++

If you write modern C++, most of Keal's memory model is familiar: shared_ptr everywhere, weak_ptr for cycles, destructors that run deterministically. What is gone is the rest of the surface — no templates to instantiate by hand, no overload resolution, no headers, no undefined behaviour.

ConceptC++Keal
Shared objectshared_ptr<T>the default
Weak referenceweak_ptr<T>weak var f: T?
Destructor~T() { }proc deinit() { }
Value structstruct P { double x; };record P(val x: Float)
Templatetemplate<class T> T f(T)func f<T>(x: T): T
Concepttemplate<Ord T>func f<T: Ord>(x: T)
Optionalstd::optional<T>T?
Lambda[&](int x){ return x*2; }{ x -> x * 2 }
Exceptionthrow / catchthrow / catch
Operator overloadoperator+trait Add
Namespacenamespace a { }one flat namespace, for now

What will surprise you

Templates without the instantiation errors

Generics are checked once at the declaration, then monomorphised. A generic that type-checks compiles at every instantiation — no pages of errors from inside a header.

No overloading, one name one meaning

Operators come from traits, and a name means one thing in a scope. It costs some expressiveness and buys back the ability to read a call site.

Pass a .cpp on the keal build line: it compiles under c++, the generated C stays C11, and only the link is shared.

Deterministic, still

deinit runs at the next statement boundary, youngest first — the same order a stack of RAII objects unwinds in.