The biggest change is that everything is checked before it runs, and types are not optional hints. The second biggest is that indentation carries no meaning — blocks are braces. What survives: readable code, interpolation, list and map literals, and a REPL.
| Concept | Python | Keal |
|---|---|---|
| Binding | x = 1 | val x = 1 |
| Rebindable | x = 1; x = 2 | var x = 1 |
| Function | def add(a, b): return a + b | func add(a: Int, b: Int): Int { a + b } |
| No return | def log(s): print(s) | proc log(s: String) { println(s) } |
| List | [1, 2] | [1, 2] |
| Dict | {"a": 1} | {"a": 1} |
| f-string | f"hello {name}" | "hello ${name}" |
| None | x = None | val x: String? = null |
| Class | class C: def __init__(self, n) | class C(var n: Int) |
| Dataclass | @dataclass class P: x: float | record P(val x: Float) |
| Comprehension | [x*2 for x in xs] | xs.map({ it * 2 }) |
You annotate parameters and fields; everything else is inferred. A mismatch is an error before the program starts, not a surprise on line 400.
Methods take no receiver parameter — this is available inside a class, and that is all. (In actor handlers you may see a parameter named self; it is a name the author chose, not a keyword.)
Int is 64 bits and overflow panics rather than promoting. Float follows IEEE 754.
Same model, same blind spot: a cycle. CPython adds a collector; Keal asks you to write weak on the back edge, and explains why in its memory document.