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

Indexing into arrays and vectors is really wise to avoid.

The same day Cloudflare had its unwrap fiasco, I found a bug in my code because of a slice that in certain cases went past the end of a vector. Switched it to use iterators and will definitely be more careful with slices and array indexes in the future.





> Cloudflare had its unwrap fiasco,

Was it a fiasco? Really? The rust unwrap call is the equivalent to C code like this:

    int result = foo(…);
    assert(result >= 0);
If that assert tripped, would you blame the assert? Of course not. Or blame C? No. If that assert tripped, it’s doing its job by telling you there’s a problem in the call to foo().

You can write buggy code in rust just like you can in any other language.


I think it's because unwrap() seems to unassuming at a glance. If it were or_panic() instead I think people would intuit it more as extremely dangerous. I understand that we're not dealing with newbies here, but everyone is still human and everything we do to reduce mistakes is a good thing.

I'm sure lots of bystanders are surprised to learn what .unwrap() does. But reading the post, I didn't get the impression that anyone at cloudflare was confused by unwrap's behaviour.

If you read the postmortem, they talk in depth about what the issue really was - which from memory is that their software statically allocated room for 20 rules or something. And their database query unexpected returned more than 20 items. I can see the argument for renaming unwrap to unwrap_or_panic. But no alternate spelling of .unwrap() would have saved cloudflare from their buggy database code.


.or_panic() would be a genuinely better name for .unwrap(). .unwrap() sounds a lot like .unbox(), whatcoulddagowrong?

The point is Rust provides more safety guarantees than C. But unwrap is an escape hatch, one that can blow up in your face. If they had taken the Haskell route and not provide unwrap at all, this wouldn't have happened.

Nope. Unwrap isn't an escape hatch from rust's safety guarantees. Safe rust mostly only makes guarantees around misuse of memory - like it guarantees you won't have use-after-free bugs, or misaligned reads, or data races. The full list of guarantees is pretty interesting[1].

Rust never guarantees that your program won't crash if it has a bug. Quite the opposite. Rust crashes in more circumstances than C code does. For example, indexing past the end of an array is undefined behaviour in C. But if you try that in rust, a rust program detect it and crash immediately. In debug mode, rust programs also crash on unsigned integer overflow.

If unwrap escaped any of safe rust's guarantees, you'd need an unsafe block to call unwrap.

[1] https://doc.rust-lang.org/reference/behavior-considered-unde...


https://hackage.haskell.org/package/base/docs/Data-Maybe.htm...

"The fromJust function extracts the element out of a Just and throws an error if its argument is Nothing."


Haskell’s fromJust, and similar partial functions like head, are as dangerous as Rust’s unwrap. The difference is only in the failure mode. Rust panics, whereas Haskell throws a runtime exception.

You might think that the Haskell behavior is “safer” in some sense, but there’s a huge gotcha: exceptions in pure code are the mortal enemy of lazy evaluation. Lazy evaluation means that an exception can occur after the catch block that surrounded the code in question has exited, so the exception isn’t guaranteed to get caught.

Exceptions can be ok in a monad like IO, which is what they’re intended for - the monad enforces an evaluation order. But if you use a partial function like fromJust in pure code, you have to be very careful about forcing evaluation if you want to be able to catch the exception it might generate. That’s antithetical to the goal of using exceptions - now you have to write to code carefully to make sure exceptions are catchable.

The bottom line is that for reliable code, you need to avoid fromJust and friends in Haskell as much you do in Rust.

The solution in both languages is to use a linter to warn about the use of partial functions: HLint for Haskell, Clippy for Rust. If Cloudflare had done that - and paid attention to the warning! - they would have caught that unwrap error of theirs at linting time. This is basically a learning curve issue.


This is the equivalent of force-unwrap in Swift, which is strongly discouraged. Swift format will reject this anti-pattern. The code running the internet probably should not force unwrap either.

Funny, it's really the same thing, why Rust people say we should abandon C. Meanwhile in C, it is also common to hand out handle instead of indices precisely due to this problem.

It's pretty similar, but writing `for item in container { item.do_it() }` is a lot less error prone than the C equivalent. The ha-ha-but-serious take is that once you get that snippet to compile, there's almost nothing you could ever do to break it without also making the compiler scream at you.

In rust, handing out indexes isn’t that common. It’s generally bad practice because your program will end up with extra, unnecessary bounds checks. Usually we program rust just the same as in C - get a reference (pointer) to an item inside the array and pass that around. The rust compiler ensures the array isn’t modified or freed while the pointer is held. (Which is helpful, but very inconvenient at times!)



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

Search: