-
Notifications
You must be signed in to change notification settings - Fork 13.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Indexed and IndexedMut traits only accept usize #29010
Comments
There's a PR implementing conversion traits There's also an RFC proposing checked integer conversions, panicking on truncation. With these conversions indexing with signed types will look like Some older discussion on this topic: |
Making the panic for the signed integer case "visible" would be inconsistent with the current behaviour for out-of-bounds large positive numbers... That is, both of these cases should "work" in the sense that both should panic, for the same reason and in the same way: let i: isize = -5;
let j: usize = 5;
let x = [0; 2];
let a = x[i]; // panic (out-of-bounds low)
let a = x[j]; // panic (out-of-bounds high) Now that I think about it, the For example, consider the case of indexing into an array using 'large' E.g.: let i: u64 = {larger than array bounds, representable within 32 bits};
let j: u64 = {too large to represent within 32 bits};
let x = [0; ...];
let a = x[i]; // slice out-of-bounds panic on any platform
let b = x[j]; // slice out-of-bounds panic on 64-bit, integer truncation on 32-bit This could cause issues for programmers relying on Ideally, any integer type should be usable for indexing, and the behaviour should always be consistent: allow the lookup if within bounds, panic with an out-of-bounds error otherwise (not an integer truncation error). |
@peter-bertok |
@petrochenkov This is a common pattern in other safe languages, such as C# or Java: try {
... complex array code for, say, decoding a packet...
} catch( IndexOutOfRangeException )
{
return ... "invalid data format"...;
} This is almost possible with (nightly) Rust, with the only minor issue that panic isn't strongly typed: #![feature(catch_panic)]
fn test( i: usize ) -> i32 {
let data = [0i32;10];
data[i]
}
fn main() {
match std::thread::catch_panic( || test( 50 ) ) {
Ok(n) => println!( "{:?}", n ),
Err(e) => println!( "{:?}", e )
}
} Unless I'm missing something, the current design for error handling in Rust has a number of gaps:
I'm of the opinion that this boils down to language design philosophy. Java, C#, C++, and Go all made the mistake of pretending that templates are an optional feature, then tacked them on too late (or not at all), resulting in poorly designed standard libraries, often with two versions of the same interface -- templated and legacy. Those language designs contained a huge mistake that can never be corrected in a backwards-compatible fashion. Thankfully, Rust implemented templates right from the beginning, resulting in a much more elegant standard library. Good! Unfortunately, the Rust designers made the mistake of pretending that exceptions are optional. They are not. Exception handling is vital to safe, readable, and performant code. Right now, developers have to sacrifice at least some of those features if they want to program in Rust because neither "Error" nor "panic!()" handle the "Exception" case well enough. Error handling with complex return types and try!() has an overhead and results in messy code, while panic just kills the program, which is a potential denial of service. How is Servo expected to decode complex binary protocols safely, such as compression formats, without killing the browser when receiving specially crafted malicious input? The compiler-generated panics will kill the thread! So should any code that can potentially cause array-out-of-bounds be run in dedicated threads!? Or should the Servo developers just use Ideally, I'd love to see Rust embrace Scoped Continuations, which is a language design that is a superset of Monads and Try-Catch exception handling. It would make it possible to write type-safe error handling that is much more powerful than the current Monadic-style that is better suited to pure functional languages. |
I think you are steering off course of this issue. This issue is about the arguments the Index types take. If you want to discuss exception handling I suggest you join the discussion: rust-lang/rfcs#243
Please provide measurable evidence ;)
Have you seen Java Code handling exceptions?
The point of panic is that it should never occur. Any time you index into an array you are "guaranteeing" that the index is in the range. If it's not, it's a bug in your code. If you want to check and change behavior depending on whether an index is in range, add a check or use a method like
Yes it does, and if you also do it, one of the two checks gets optimized out. Often times both get optimized out if llvm figures out that neither check is necessary. |
Regardless of opinions, this change would require an RFC. Feel free to open an issue (or better yet, an actual RFC) over on https://github.com/rust-lang/rfcs if you want to continue this discussion. |
Sample code: https://play.rust-lang.org/?gist=b9b0fad33060c74095a0&version=nightly
Short sample code that fails to compile:
I'm working on a native Rust implementation of the Google Brotli compression algorithm (https://github.com/peter-bertok/brotli), which has a lot of low-level bit/byte twiddling and came across this issue.
repr(C)
enums.u8
,u16
, andu32
.usize
, like they have to do now. This would wrap to a small positive number, which is a valid index. If the rust compiler provides an implementation forIndexed<>
with signed types, it can insert a check for negative numbers, improving safety substantially. Currently, this compiles and runs without a panic:usize
type unexpectedly, which is confusing to developers. Goes against the rule of least surprise. This fails to compile unexpectedly:Proposal
Indexed
andIndexedMut
traits foru8
,u16
, andu32
for slice and Vec types with identical behaviour to theusize
version.Indexed
andIndexedMut
traits forisize
,i8
,i16
, andi32
for slice and Vec types with new behaviour that panics on negative values, not just out-of-bounds positive values.i64
andu64
implementations are problematic on 32-bit builds. How these are treated is up for debate.The text was updated successfully, but these errors were encountered: