Though it's not the only benefit, I enjoy rust and fsharp's typesystems most when refactoring code. Fearless refactoring is the right expression here.
replies(1):
On the other hand, that strictness is precisely what leads people to end up with generally reasonable code.
match foo {
(3...=5, x, BLABLABLA) => easy(x),
_ => todo!("I should actually implement this for non-trivial cases"),
}
The nice thing about todo!() is that it type checks, obviously it always diverges so the type match is trivial, but it means this compiles and, so long as we don't cause the non-trivial case to happen, it even works at runtime. fn foo() -> impl Display {
NotDisplay::new()
}
and a test references `foo`, then it gets replaced for the purposes of the test with fn foo() -> impl Display {
panic!("`NotDisplay` doesn't `impl Display`")
}
This should not be part of the language, but part of the toolchain.Same thing for the borrow-checker.
Although you said "mode of operation" and I can't get behind that idea, I think the choice to just wrap overflow by default for the integer types in release builds was probably a mistake. It's good that I can turn it off, but it shouldn't have been the default.