Tricky subject.
Consider that you have the following function somewhere:
fn some_function_somewhere<T:Eq>(x: T, y: T) { ... }
and suppose you have some PartialEq
type that you want to use it on. I think this signature can probably be loosened, you think. So you change the Eq bound.
Say this results in a type error because some_function_somewhere
calls another function with an Eq
bound. So you look at that function, review it, and remove the type bound. This produces more type errors, and you repeat the process so on, and so on, though a fairly mechanical process...
...until eventually, you find yourself looking at a function which actually does rely on the fact that x == x
.
Snap.
So what happened here?
By encoding various assumptions in type signatures, rust helps you validate whether a new feature fits into the existing design by forcing you to visit each part of the code that it impacts. In this manner, the type system eliminates mental overhead by letting the type system do most of the thinking for you.
...however.
Now it is your responsibility to realize and remember that the T:Eq
bound is fundamentally necessary, so that you don't make the mistake of trying to remove it again.
In this manner, one kind of mental overhead is removed; but another remains.
With regards to productivity... well, I find rust sometimes is detrimental to productivity on small projects. I find myself overengineering some solutions in ways that really don't matter in the long run.
Whether this is due to me or rust, I'm not sure; but in any case, I suppose that, despite rust's focus on correctness, one must retain that ability to recognize those times when a duct tape solution actually does suffice.
(such as things that nobody else besides you will ever use, which does constitute about 99% of the code I write in my discipline...)