I was very surprised that the std library's split_off function could panic if the provided index is out of bounds (see Vec in std::vec - Rust).
Is there a design reason why this function doesn't return a Result or an Option? panicing seems very unidiomatic, and most other Vec functions seem to return Results/Options instead of panicing.
IMO that was an oversight. [T]'s split_at method also panics if the index is out of bounds, it's likely that the same contract was copied for consistency. Now it can no longer be changed though.
I'd say panicking API would have to take into consideration a few things like
how often would use-cases need/want to just call .unwrap() anyways because they already know that the failure is impossible for them?
how easy is it to do the check that prevents the panic manually before you call the API?
on that note, is it even an API that has the structure (1) check precondition (2) panic and do nothing else if precondition fails (3) do actual operation?
and how much overhead is it if the check is duplicated like this (since the second check for potentially triggering the panic doesn't go away)
With splitting of slices/vec, it's certainly quite common that your index calculations that determined the index you're interested in are done in a way that you know the index is going to be in-bounds anyways. Whether it's common enough to warrant the additional complication of needing manual checking for users that don't know the in-bounds-ness beforehand, is a different question. At least the index < v.len() check is cheap and easy to write (and likely optimized away if duplicated) and thus it's checking a lot of boxes in my above list for criteria when panicking behavior could be reasonable.
Another alternative to consider would be to offer both a panicking and a Option-returning API. This would e.g. be the case for indexing where we have subscript-operator (&v[ix]) as well as a non-panicking alternative (v.get(ix)) and this way the (possibly) more common case where you already know your index is in-bounds doesn't get super verbose (not v.get(ix).unwrap() but just &v[ix]).
Whether the current API for the split methods that take a usize index and panic on index out of bounds was a mistake or oversight, I'm not sure. I'd say it's a trade-off, and possibly one that would be decided the other way if the API was designed anew today ... but then again maybe not even that.
" Functions often have contracts : their behavior is only guaranteed if the inputs meet particular requirements. Panicking when the contract is violated makes sense because a contract violation always indicates a caller-side bug and it’s not a kind of error you want the calling code to have to explicitly handle. In fact, there’s no reasonable way for calling code to recover; the calling programmers need to fix the code."
Most of the time when you're doing indexing, you have an implicit algorithm invariant that the index is in-range. And thus you'd just be typing .unwrap() anyway.
Plus indexing is easy to check yourself before if you need it, and doing so will let LLVM optimize out the panic -- like like how assert!(x.len() > 10) will optimize out the bounds checks in x[0] + x[10].