Coming from Kotlin

Keal borrowed Kotlin's shape on purpose: val/var, ? in the type, when, smart casts, data classes, trailing-lambda ergonomics. What it did not borrow is the JVM, the extension functions, the coroutines, and the second way to say things.

ConceptKotlinKeal
Bindingval x = 1val x = 1
Data classdata class P(val x: Int)record P(val x: Int)
Nullableval s: String? = nullval s: String? = null
Safe calls?.lengths?.length
Elviss ?: "d"s ?: "d"
whenwhen (n) { 0 -> … }when (n) { 0 -> … }
Functionfun add(a: Int): Int = afunc add(a: Int): Int { a }
Unit functionfun log(s: String) { }proc log(s: String) { }
Lambdaxs.map { it * 2 }xs.map({ it * 2 })
Interfaceinterface Ordtrait Ord
Coroutinelaunch { … }sys.spawn({ self, msg -> … })

What will surprise you

proc is the missing half of func

Kotlin writes fun f(): Unit; Keal writes proc f() and refuses to let you use its non-result. Unit never appears in a program.

No extension functions, no operators by convention

Operators come from eight traits (Add, Ord, …) that your type implements explicitly. There is one place to look for what + means.

Concurrency is actors, not coroutines

spawn a handler, send messages, run. Compiled natively each actor is an OS thread; the interpreters run a deterministic schedule, and both print the same bytes.

Logic is spelled out

and, or, not — plus xor, nand, nor, xnor and implies, all at one precedence, so mixed expressions need parentheses.

So are the bits

band, bor, bxor, bnot, shl, shr, ushr. Kotlin spells them as infix words too; Keal adds that they mix with nothing without parentheses, and that they bind tighter than == — so flag band 2 != 0 means what it looks like.