Earlier quoted context omitted.
> the compiler will statically guarantee the impossibility of null dereference exceptions, almost every language that gets rid of nulls with something like the Option type will let you still bypass it and get a null reference exception. Rust lets you unwrap, F# lets you bypass it. You could at least enforce a lint that doesn't allow the bypasses in projects where that is desired though.
Perfect is the enemy of good. By reducing the possibility of null dereference exceptions from 100% to 10% you have reduced the cognitive burden by 90%. Removing the bypass would result in a 100% reduction in cognitive burden, only 10% more than the second best solution. However handling null cases correctly isn't free either. Especially when you know that a value cannot be "null" under certain conditions which those…
While I agree there are rare cases where .unwrap() is the right thing to do, I actually disagree here that it’s anywhere close to 10%: If you want to write a function that accepts only non-null values in Rust, you simply write it as such! In fact, this is the default, and no cognitive burden is necessary: non-nullable T is written simply as “T”. If you have an Option and want to convert it into a T in Rust, you simply use “if let” or “match” control flow statements.
I actually think using .unwrap() in Rust anywhere but in test code or top-level error handling is almost always a mistake, with perhaps 0.001% of exceptions to this rule. I write code that never uses it, except those cases mentioned; while I’ve run into situations where I felt at first .unwrap() was appropriate, I took a step back to think of the bigger picture and so far always find safer solutions to yield a better overall design.
The cognitive burden from Rust comes not from this, but almost entirely from the borrow checker (a completely different toptic), and in some cases, arguably inferior “ergonomics” vs how Zig or Kotlin handle optionals.
For example, in some null-safe languages, you can write:
if (myObject) { myObject.mehod(); }
And the compiler will understand this is safe. Whereas, in Rust, you must write: if let Some(x) = myObject { x.method(); }
This is not even to mention that Rust has no built-in shorthand for Option (some languages write “T?” for example), but I understand why they chose not to build this into the language; rather, Option in Rust is actually a component of the stranded library! In a way, that’s actually quite cool and certainly is by-design; however, it doesn’t change the fact that it’s slightly more verbose.IMO it’s not a huge deal, but certainly Rust could benefit from some syntax sugar here at least. Either way, both examples here are safe and statically checked by the compiler.