12 ms·
But if you are a mid-level consumer, you don't know whether you can pick the panicky or the non-panicky API. Do you provide 2 APIs again?
by spion 10y ago
But if you are a mid-level consumer, you don't know whether you can pick the panicky or the non-panicky API. Do you provide 2 APIs again?
- Manishearth 10y agoNo, you provide the non-panicky API, consumers can convert those into panics easily. In Rust, if your API uses monadic error handling (Result or Option), this is easily chained with other errors and propagated up. Additionally, callers can choose to discard errors they feel should not happen by using unwrap/expect to convert them into panics. If your API uses panics, this can't be cleanly turned into non-panicky things without using catch_unwind (you can, but you shouldn't). In the rare case you make the decision to have an ergonomic panicky API, try to provide a slightly less ergonomic non-panicky one.
- spion 10y agoSo 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.
- Manishearth 10y agoI 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.
- spion 10y ago`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.
- Manishearth 10y agoNot 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.
- spion 10y agoWhy is the program in an inconsistent state when it attempts to access an array out of bounds and is prevented from it?
- Manishearth 10y agoBecause 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.
- spion 10y agoThis "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.