Hacker News new | past | comments | ask | show | jobs | submit login

So ultimately the reason for providing a panicky API has nothing to do with expectedness, its actually all about performance. Otherwise we'd always go for a non-panicky one.

Also, in languages with finally and/or defer, catch isn't supposed to be a problem.




I never said that.

Not performance, ergonomics. `array[5]` and `array.get(5).unwrap()` do the same thing (with a different panic message) and have the same performance when optimized (since it should inline). It would be annoying to have to handle the error every time you index, and would kind of ruin the syntactic sugar of indexing. Thus, indexing panics, and you have `.get()` if you want to not panic and use monadic errors (but as you can see, you can make `.get()` panic too by unwrapping it).

The same goes for other panicky APIs, they're panicky because 99% of the time you don't want to deal with that error since it's an "unexpected" one which means something went horribly wrong and there's no sane way to continue. For the 1% of the time you do need to deal with that error, you can use the alternate Result/Option-based API.


`try!` seems like sufficient sugar to deal with the ergonomics part.

> and there's no sane way to continue

Would like to hear more about this.


Not really, you have to change the return type of all of your functions and introduce new error types.

There's no same way to continue in cases where an out of bounds access is a program bug. What should a program do when it knows it is in an inconsistent state? Crash, in many cases.


Why is the program in an inconsistent state when it attempts to access an array out of bounds and is prevented from it?


Because it was designed assuming that the array would not go out of bounds. If an array did go out of bounds, clearly something has gone horribly wrong.

This is a question of how the software was designed and what assumptions were made.

In a case where the programmer feels that out of bounds may happen (or wishes to program defensively), of course the usual monadic error APIs can be used instead of indexing directly.


This "clearly something has gone horribly wrong" is where I think we actually get lazy.

Let me illustrate using my example. The mid-level consumer is a crop function that takes the image and coordinates. It has no reason to assume someone wont check the image bounds so it uses the panicky API to access the array, assuming "Ok, they'll check if they are out of image dimensions beforehand".

But another level up, we're passing user-generated data right to it, after the face detection crop. Clearly thats wrong. Unfortunately the mid-level consumer didn't provide a non-panicky API so we had to write our own wrapper.

The question is, is it crashy-wrong? If shared mutable state is cleaned up via RAII/defer/finally, there is nothing wrong with the "exception" being caught and the process can continue running. The reason why we don't know if something went horribly wrong is that we don't have the cleanup contract for handling these types of things in the first place.

So why do we want this extremely unsafe "cleanupless" contract to begin with? I can't think of any other reason than performance, because syntax sugar can always take care of the rest.


> Ok, they'll check if they are out of image dimensions beforehand

that's a straw man example, its not the kind of API I'm talking about.

Let me repeat: this is for cases where the library developer has written code where it won't go out of bounds, and if it does it's a bug in their own library. Not the input. Rust APIs are not designed the exception-way where unexpected input is supposed to be caught like exceptions.

For example, I may allocate a buffer of size n, and index it willy nilly at various points I know to be less than n (perhaps, for example, values from another array which was constructed with values not exceeding n). If this doesn't work, it's a bug in your program and there no two ways about it. The assumptions you made about your own program when writing it were wrong. This can happen if you make a mistake when programming, or mess up a refactoring, or rely on a library that changes behavior (which itself shouldn't happen but the world isn't perfect).

Almost all of the indexing panics I've seen in Rust have been bugs in the code that was indexing; where continuing the program somehow would probably make things worse since the state is inconsistent (according to the assumptions the programmer made about their own code, not the input). People tend to use `.get()` when it's possible that the input may trigger an out of bounds error.

Its not a performance issue; the bounds check happens either way, please stop making it one. Its an ergonomics issue. Rust tries to offer both imperative and functional styles, and also tries to be palatable to people from C++. This leads to some C++-like defaults like the indexing syntax. If people had to unwrap/try on every index in rust half the community would probably revolt.

(note that indexing isn't that common; rust uses iterators and other safer, bounds-check-contained abstractions, but it was determined that when you want to use direct indexing in Rust you usually are designing your code such that the out of bounds is a bug)




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

Search: