Unfortunately, Rust is not magical.
Detecting these errors at compile time, carries a number of significant trade-offs. First of all, the majority of out-of-bound cases cannot even be detected, since they either have an arbitrary value or a very little constrained one. This means that they have no usable bound, and thus no data to argue about the value, or a potentially OOB (which is actually unreachable).
So, this will in the majority of cases force the programmer to make a bound check anyways (through a if
or match
), providing no better or worse performance than the implicit one.
“Free” manual checks are already possible through the widely-used get()
method.
For statically detecting out of bound conditions, you’ll have to introduce a number of otherwise ineffective constructs to the type system:
-
Non-local typestate analysis. Meaning that you cannot analyze on a function level. You’ll have to type check the program as a whole. This has an exponential complexity. For any non-trivial program the compile time will sky-rise (my guess is about 50-70x). Typestates have been proven ineffective over time, due to its many limitations, especially since it is an extremely “pessimistic” form of analysis. Typestate bound checking is a very stupid one compared to, for example, LLVMs bound check elision which is very sophisticated and extensive one, so chances are that you’ll not get any advantages of a typestate bound checking over LLVMs optimizations.
-
Structural (non-lexical) subtyping. This is a very complex construct to introduce in a type system with efficient type inference. Type inference will be practically impossible with this kind of structural subtyping.
-
Non-trivial dependent typing. You’ll have to argue about the state of the program based on the control path, information about the previous states of the program, non-local type information, and. This construct severely increases the complexity and compile time of the language.
There are so many things, you have to trade for a mostly useless mechanism, which will enforce the programmer to do the bound check manually most of the time anyways.
A 100 times easier, yet just as efficient, solution is to remove panicable Index
, but that seems like a bad idea too, since OOB is normally unrecoverable, and using get()
will make the language very verbose.
So while it is possible to create a mechanism which detects OOB, it cannot be perfect (it’ll have false positives), since the problem is undecidable. The best and simplest solution is range constraints for integers, but even that is almost useless, due to most integer being arbitrary.
A lint for const exprs is certainly possible, but a generalized solution is not. I’m sorry, but Rust cannot solve the halting problem (I wish it could ).