4 ms·
There are other good comments here, but the use case where I find it most important is in lambdas. What do you do when a lambda throws an exception in the proce
by bluejekyll 10y ago
There are other good comments here, but the use case where I find it most important is in lambdas. What do you do when a lambda throws an exception in the processing loop of an iterator?
some_vec.iter().filter_map(|i|
i.to_something()
.map_err(|e|None)
.map(|i|Some(i)))
.collect()
I think that will compile. The `to_something()` might return an error, the important thing is that there is no exception and allows for clean error handling. In this case we're just ignoring errors. With exception handling, while it's not impossible to do the exact same thing, I believe this is cleaner (and yes, there are other ways to write this).
- pjmlp 10y agoC#, C++, Java, F#, OCaml, Haskell, Lisp try_block some_vec.iter().filter_map(|i| i.to_something() .map_err(|e|None) .map(|i|Some(i))) .collect() catch_exception
- bluejekyll 10y agoThis is not correct. The to_something() is what throws the exception. In those languages, you need to put the try block inside the iterator's map lambda. Again, I didn't say it was not possible in the other languages, I only stated that I didn't think it ends up being as clean (specifically in regards to C++, Java and C#)
- gpderetta 10y agoIn most languages, it is easy to write a 'try(expr, fail)' HOF that gives you the same functionality (but possibly with different performance profiles, depending on the underlying exception handling implementation). On the other hand without non-local error handling it is harder to bail out of the outer map on a to_something error, if that's what's desired.
- junke 10y agoIn Lisp the "catch" part could be "handler-bind", which could invoke a restart (skip element, or use-value). This requires the called function to establish a restart, but the good news is that it removes the burden of the decision from the innermost part.
- pjmlp 10y agoSo what, I don't care where the error occurs. Either the full expression is successful or not.
- bluejekyll 10y agoWhat we are debating at this point is style. I offered something which I think is cleaner than what I see in other languages. You don't see the point, and that's fine. Initially when Java came out with Streams I hadn't worked a lot with ETL like functions. Then while with Rust I really got it, so now I want to apply that practice to code in Java, because it simplifies many areas of code. One thing that became very clear, is that Exception handling throws a minor monkey wrench into keeping the code simple. This is why I picked the example I showed. You don't think it's cleaner, or makes a big difference, and that's fine. I personally find it to be easier to read and create more understandable code. You can have your exceptions, but after Rust I am totally sold on the Result for errors pardigm.
- pjmlp 10y agoI don't think it is cleaner, because usually we architect our applications in logical blocks. For example when sending a data packet over the network and it fails, I don't care if the error was in the communication, buffer, socket level or network layer, just that the packet could not be sent. That is what we need to retry, sending a new packet, not the lower level operations. Languages with exceptions, which I use since 1993, allow me to choose using an exception, transform it into a plain error code or monadic error. I can have it all and choose which flavour I want to use, depending on the use case. But as you say, it is a matter of style.