4 ms·
you can map on ok which is an alias for map_ok and then map_err for errors and or_else or_throw etc. that's similar to what Java does with the Optional type, n
by peoplefromibiza 5y ago
you can map on ok which is an alias for map_ok and then map_err for errors and or_else or_throw etc.
that's similar to what Java does with the Optional type, not great, but not bad either
the alternative is checking for nulls which is worse in any possibile way
I usually implement something like Kotlin Result when I have to code in Java
with a couple of static helpers to build the result: Result.success(T) Result.failure(Throwable t)
https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-result/ https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-result/
also Result in Rust has been an inspiration
https://doc.rust-lang.org/std/result/enum.Result.html https://doc.rust-lang.org/std/result/enum.Result.html
- linkdd 5y agoI also made a library for working with `{:ok, value}` and `{:error, reason}` in Elixir: https://github.com/linkdd/rustic_result https://github.com/linkdd/rustic_result Thanks to the pipeline operator and pattern matching, it makes pretty easy to read pipelines. It does not completely replace the with statement (that was not the point) but it simplified a lot of code.
- peoplefromibiza 5y agothis is nice, especially for the function clauses Elixir is my daily drive and working in Java made me miserable until I started working around the lack of pattern matching facilities Error handling is the worst part, I think a simple switch (retval) { Ok(val): ... break; Error(err): ... would make Java much more pleasant, even without full pattern matching everywhere.
- crdrost 5y agoThis sorta exists in Java 17: sealed interface Result<T> permits Ok, Error {} record Ok<T>(value: T) implements Result<T> {} record Error<T>(error: Throwable) implements Result<T> {} // to consume switch (result) { case Error e -> e.error().getMessage(), case Ok v -> v.value().toString() }
- kaba0 5y agoNitpick, but I like to point out that Java’s exceptions are themselves a Result type/analog with them. You can unwrap it by a try catch, and can choose to rethrow it with minimal syntax. It even has a plus, it will auto-attach a stacktrace to the error case.
- saghm 5y agoThis is only the case for "checked" exceptions though; the important part about the Result type in Rust is that it won't implicitly propagate errors if you try to just use the success value but instead will give a compiler error. I don't code much Java, but my impression is that standard library methods throwing unchecked exceptions is far more common than panicking, the closest equivalent is in Rust.
- absove 5y agoNot so much a nitpick because with checked exceptions your method signature can declare multiple types of exception whereas Result generalizes your specific exceptions to Throwable, which you can't pattern match with the compiler being able to enforce exhaustiveness. So to achieve the same exhaustiveness as a method like User createUser() throws IOException, BusinessException you would need both a Result-like construct and union types Either<User, IOException | BusinessException> createuser() which few mainstream languages offer. Otherwise you type is unable to express that only IOException and BusinessException are thrown and you don't need to handle a default Throwable case.
- peoplefromibiza 5y agochecked exceptions don't integrate very well with streams and reactive pipelines, to the point that basically all of then end up being wrapped and rethrown as unchecked methods that declare checked exception can throw RuntimeException(s) so exhaustiveness cannot be totally enforced anyway