4 ms·
The right thing is to automatically maintain error context (e.g. stack traces) which golang fails at. Furthermore, the vast majority of the time you will have a
by azth 5y ago
The right thing is to automatically maintain error context (e.g. stack traces) which golang fails at. Furthermore, the vast majority of the time you will have a top level handler that will log the error anyway. golang is just introducing boilerplate for the sake of it, with none of the upsides. Not to mention it also makes it easy to accidentally ignore or overwrite errors, I've seen several instance of that happening over several years of working in golang. Something that would never have happened in an exception based language.
- morelisp 5y ago> Something that would never have happened in an exception based language. Please, over-swallowed exceptions happen all the damn time. Same shit different day. A really common Java problem: T x = foo(); return x.bar(); Now foo() can throw, OK try { T x = foo(); return x.bar(); } catch (Something exc) { return quux(); } You just ate anything from bar(). Instead you gotta do T x; try { x = foo(); } catch (Something exc) { return quux(); } return x.bar(); Which is longer and now your happy-path logic is noised up even worse than most Go handling.
- smw 5y agoOnly with checked exceptions, which I think most of java has made an anti-pattern now?
- morelisp 5y agoNo, it's got nothing to do with checked exceptions. It's from not wanting all the error-handling noise between the two steps of your happy-path logic. And at least in extant Java code and many Java programmers I interview, it's not considered an anti-pattern (but I agree it should be).
- azth 5y agoIt's quite trivial to write a generic function that handles a particular exception else returns a default value, which addresses the above scenario. final var x = getOrDefault(C::foo, Something.class, quux()); return x.bar(); And now with pattern matching in Java, it's trivial to write something similar to Rust's/Scala's `Result<T, E>`/`Try<T>` types and be explicit about all exceptions. I haven't compiled the following, but it's along the lines of: final var x = switch (foo()) { case Ok(var r) -> r; case Error e -> quux(); } return x.bar();
- morelisp 5y agoNeither of those is equivalent to what I wrote (in different ways!), and the first one doesn't even work because of type erasure - you can't write generic functions over exception types. You're also focused way too much on the specific lines I wrote and not the general pattern that leads to exception over-handling. > trivial... trivial Rethink your use of this word. Anyway, alternative proposals don't really matter - I could also offer patterns for Go which make accidentally ignoring error values more difficult. We're talking about actually extant code, and nobody writes Java (or Go) like that outside of forum arguments.
- azth 5y ago> and the first one doesn't even work because of type erasure - you can't write generic functions over exception types. It sure does work :-) @FunctionalInterface interface ThrowingSupplier<R, E extends Exception> { R get() throws E; } static <T, E extends Exception> T getOrDefault(ThrowingSupplier<T, E> f, Class<E> exceptionType, T def) throws E { try { return f.get(); } catch (Exception e) { if (exceptionType.isInstance(e)) { return def; } throw e; } } > and nobody writes Java (or Go) like that outside of forum arguments. https://www.javadoc.io/doc/io.vavr/vavr/0.9.3/io/vavr/control/Either.html https://www.javadoc.io/doc/io.vavr/vavr/0.9.3/io/vavr/contro... And now that Java has sealed types and pattern matching, it might become more popular. Kotlin already has them (even without the exhaustive pattern matching that Java has): https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-result/ https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-result/