Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

> First of all, they kind of dodge this later by saying "Array indexing must be properly tested" (else it can panic) -- everyone thinks they write code which is "properly tested".

You're skipping half the recommendation though:

> Array indexing must be properly tested, or the get method should be used to return an Option.

emphasis mine

> Also, in rust if we don't want to panic we need to never use array indexing and never use integer division, just to start.

I mean, that's literally the block above the one you quote:

> Common patterns that can cause panics are:

> * using unwrap or expect,

> * using assert,

> * an unchecked access to an array,

> * integer overflow (in debug mode),

> * division by zero,

> * large allocations,

> * string formatting using format!.

>> Rule LANG-NOPANIC

>> Functions or instructions that can cause the code to panic at runtime must not be used.

The bit you quote is really a additional reminder that array indexing is not panic-safe.



Saying "properly tested" doesn't seem useful to me. What is "properly tested"? I'm sure people thing most array overflows in C libraries are "properly tested", as noone wants to cause memory corruption.


> Saying "properly tested" doesn't seem useful to me. I'm sure people thing most array overflows in C libraries are "properly tested"

It is useful in the sense that it's for a restricted set of constructs, in the same sense that `unsafe` blocks are not outright forbidden but they should be justified and because they're restricted in span they can be more easily tested than your entire C codebase.

Since array indexing would be recommended against by default (and either iterators or `get` would be the normal way to handle it), the number of places where it is used should be small and thus easy to check for, and test extensively if not exhaustively.


What do you do when your algorithm works with array indexing and you are never supposed to handle than None within the Option?

Ie if you have indexed array out of bounds that’s a developer’s mistake and not a “condition to be handled up the stack”.

It’s ok to panic if you agree that it’s better to panic rather than end up in a state that will probably cause even more issues down the line


> What do you do when your algorithm works with array indexing and you are never supposed to handle than None within the Option?

That's where the first clause comes into play:

> Array indexing must be properly tested

Although

> Ie if you have indexed array out of bounds that’s a developer’s mistake

Which developer would be my question.

If it's the person who reified the "algorithm [which] works with array indexing" then fair's fair, it's a bug in the implementation and should not happen, which is why the guideline specifically says:

> should never use functions or instructions that can fail and cause the code to panic

which, assuming the word is used in the RFC 2119 sense means there can be case where calling panic-ing functions is the right thing to do.

If it's the developer who calls the function implementing the algorithm, then either algorithm is failable (and thus so's the function) or the algorithm should take in more specific data structures which statically exclude failing cases. For instance `max` on an empty collection will fail, so either `max` should be failable (which e.g. `Iterator::max` is) or it should only be callable on some sort of `NonEmpty*`.


You're skipping half the recommendation though:

> Array indexing must be properly tested, or the get method should be used to return an Option.

Fwiw, for anyone who’s dabbled with Haskell this is SOP. Any result that could be undefined is returned as a Maybe (Haskell’s version of Option). If this seems odd to anyone, understanding it in Haskell will probably help understand it better in Rust too:

http://learnyouahaskell.com/a-fistful-of-monads#getting-our-...

https://en.wikibooks.org/wiki/Haskell/Understanding_monads/M...


Er, don't Haskell's head and (!!) functions default to throwing an exception?

    $ ghci
    Prelude> let a = [3, 4, 5]
    Prelude> a !! 0
    3
    Prelude> a !! 3
    *** Exception: Prelude.(!!): index too large
    
    Prelude> head []
    *** Exception: Prelude.head: empty list
I don't think Haskell is really different from Rust in this respect. Both have a wrapper type for optional values with good syntax, but in both, there's still some syntax so common operations sometimes choose to skip it.

In fact, Hoogle doesn't seem to find me a function like Rust's .get() in the standard library, just a handful of third-party packages: https://hoogle.haskell.org/?hoogle=%5Ba%5D+-%3E+Int+-%3E+May...


This was posted on /r/rust a couple days ago: https://notes.iveselov.info/cheatsheet-rust-option-vs-haskel...


> Hoogle doesn't seem to find me a function like Rust's .get() in the standard library

In practice, you don't really need one - the safe alternative to "xs !! n" is pattern-matching on the result of "drop n xs", as that's [] if xs has ≤n elements:

https://www.haskell.org/onlinereport/standard-prelude.html#$...


Sure, that seems syntactically more cumbersome than 'if let Some(foo) = xs.get(n)' or 'xs.get(n).map(|foo| ...)' in Rust, but yes, you can do it. As I said, because both the Rust and Haskell versions are more cumbersome than using the version that raises an exception/panics, both Rust and Haskell's standard libraries choose to give you a syntactically-easier alternative that isn't a total function.

All I'm saying is that Haskell doesn't seem to do anything different here - Rust has incorporated the lessons from Haskell's type system. (As someone who fell in love with Haskell a long time ago but never got to use it professionally, this is basically why I like Rust.) Is there something Haskell does that Rust does not do? I'm not trying to say Haskell is insufficient - I'm just refuting the claim that Rust is insufficient and should act more like Haskell.


Sure, I don't disagree - I meant only to add context for anyone reading who was unfamiliar with Haskell, lest they come away with the impression that the lack of a .get()-equivalent was some kind of egregious oversight.


> In practice, you don't really need one - the safe alternative to "xs !! n" is pattern-matching on the result of "drop n xs", as that's [] if xs has ≤n elements:

Great so instead of `xs !! n` you're supposed to write

    case drop n xs of
        [] -> …
        x :: _ -> …
that seems… less than likely?


> Fwiw, for anyone who’s dabbled with Haskell this is SOP. Any result that could be undefined is returned as a Maybe (Haskell’s version of Option).

It would be nice if that were true but that ain't exactly the case is it?

AFAIK exhaustive pattern matching still isn't enabled by default, and the prelude is full of partial functions, especially on lists (to such an extent that GHC has a utility function just for blowing up on empty lists: https://hackage.haskell.org/package/base-4.12.0.0/docs/GHC-L...)


There’s a number of functions that panic in the std if misused, for example copy_from_slice


Yes?




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: