Coming from Go

Both languages are small on purpose and compile to native code. Keal differs in three big ways: nullability is in the type instead of every pointer being nil-able, generics compile to one copy per instantiation, and failure is a throw you catch rather than a second return value.

ConceptGoKeal
Bindingx := 1val x = 1
Mutablevar x = 1var x = 1
Structtype P struct { X int }record P(val x: Int)
Methodfunc (p P) Len() intfunc length(): Int (inside the class)
Interfacetype Ord interface { … }trait Ord { … }
Nilvar s *string = nilval s: String? = null
Errorv, err := f(); if err != niltry { f() } catch (e) { … }
Slice[]int{1, 2}[1, 2]
Mapmap[string]int{"a": 1}{"a": 1}
Goroutinego work(ch)sys.spawn({ self, msg -> … })
Switchswitch n { case 0: }when (n) { 0 -> … }

What will surprise you

Errors are thrown, not returned

throw "…" and try { } catch (e) { }, on all three engines including native code — where it compiles to checked unwinding rather than to setjmp.

Generics are monomorphised

One C function per instantiation, no boxing, no dictionary passing. firstOr<T> used at Int and String becomes two plain functions.

Actors instead of channels

There is no select and no channel type. An actor owns its state, messages are deep-copied on the way in, and the checker refuses a handler that reaches for shared mutable state.

Build a Go package as a c-archive and hand it to keal build; the example in the repository does exactly that.