Easy to understand
You write what should happen, and Nikaia works out the technical details other fast languages make you spell out. When something is wrong, it tells you in plain words what to change.
Three ways the language stays out of your way.
Code that waits needs no marking
You do not need await, because the compiler finds where a function pauses. A call that waits pauses its function while the program goes on with other work, and it is written like any other call. A function that starts to wait leaves its callers as they are. A function marked sync is held to never waiting, and may call only other sync functions.
To run things beside each other, the specification puts async before an expression: it starts at once, and the program waits for the value where it is first needed. That form is being built (#983); today the same is written with an overlap block, which runs its lines together and waits for all of them.
let user = async db::load_user(id)
let rights = async db::load_rights(id)
let prefs = cache::load_prefs(id) // runs while both load
render(user, rights, prefs) // waits for both firstThe design being built, not accepted by today’s compiler.
Readable errors
A compiler message that talks about lifetimes and borrowing sends you away from your own code.
What Nikaia checks. The compiler points at every place the explanation needs: ^ under the line with the mistake, - under the line that explains it. Then it says what to write instead. Errors point at your .nika line and do not talk about lifetimes or borrowing.
The limit. When no line of yours explains an error, the message says so. Where a check passes a problem on to the Rust compiler underneath, the error it raises is reported against your .nika line.
error[NK1139]: You're changing `count`, but it wasn't declared as mutable.
help: Add `mut` where it's declared: `let mut count`.Formats are part of the language
Reading a log, a protocol or a small language usually means a parsing library, or a parser written by hand.
What Nikaia checks. You describe the format as a grammar, and the compiler builds the parser. Precedence and recursion are rules: the order of the rules is the order of binding. The whole calculator is about 100 lines.
The limit. A grammar is a large topic, and this page shows only the idea. The full rules are in Part II, chapter 10.
grammar Calc {
entry rule expr -> i64 =
head:term tail:add_tail* { … }
rule add_tail -> i64 =
"+" t:term { t }
| "-" t:term { -t }
}