But yes, there is still a lot of it.
Anyway, most of the noise comes from the fact that Rust is a low level language that cares about things like memory management. It's amazing how one is constantly reminded of this by the compiler, what is annoying, but the reason it doesn't happen on the alternatives is because they never let you forget about that fact.
For instance a function which returns an optional pointer to a 'Bla':
fn make_bla() ?*Bla {
// this would either return a valid *Bla, or null
}
A null pointer can't be used accidentally, it must be unwrapped first, and in Zig this is implemented as language syntax, for instance you can unwrap with an if: if (make_bla()) |bla| {
// bla is now the unwrapped valid pointer
} else {
// make_bla() returned null
}
...or with an orelse: const bla = make_bla() orelse { return error.InvalidBla };
...or if you know for sure that bla should be valid, and otherwise want a panic: const bla = make_bla().?;
...error handling with error unions has similar syntax sugar.It's probably not perfect, but I feel that for real-world code, working with optionals and errors in Zig leads to more readable code on average than Rust, while providing the same set of features.
The main difference I see is that in Rust it will also work with your own custom types, not just optional.
fn make_bla() -> Option<Bla> {
// this either returns a valid Bla, or None
}
if let Some(bla) = make_bla() {
// bla is now the unwrapped valid type
} else {
// make_bla() returned None
}
..or with the '?' operator (early return) let bla = make_bla().ok_or(InvalidBla)?;
..or with let_else (nightly only but should be stable Soon(tm)) let Some(bla) = make_bla() else { return Err(InvalidBla) }
..or panic on None let bla = make_bla().unwrap(); ??i32 const assert = @import("std").debug.assert;
fn get12() i32 {
const opt_opt_val: ??i32 = 12;
const val = opt_opt_val.?.?;
comptime assert(val == 12);
return val;
}
[https://www.godbolt.org/z/oncd5shvP]