Don't use `Throwable` ! <https://ivan.canet.dev/b...
# feed
c
👍 9
👍🏼 2
K 5
y
Arrow's
nonFatalOrRethrow
helps a lot in these situations. It's a shame that stdlib's
runCatching
can swallow exceptions in such a way, but it makes sense for its intended usage (coroutines)
âž• 1
d
Good write up! 👍
s
I don’t completely agree. Catching Throwable around the main() method can be a good practice in certain scenarios, primarily because it ensures that any unexpected exception or error is logged, giving you a chance to analyze the failure later. While it’s generally advised not to catch Error types, there are specific cases where doing so is justifiable. For instance, take UnsatisfiedLinkError. If a DLL fails to load, the default behavior would be for the program to crash. Instead of letting that happen, I prefer to catch this error and show a meaningful message to the user. In some cases, I can switch to an alternate implementation - perhaps a slower, less efficient Java-based solution - rather than immediately exiting. A similar approach is often used in libraries that provide fallback mechanisms when native code is unavailable. There are also ways to handle an OutOfMemoryError gracefully. If the try block is carefully structured to manage memory resources, it’s possible to recover and allow the program to continue functioning in a degraded state. For example, reducing the memory footprint by clearing caches or offloading tasks might allow the application to survive long enough for proper intervention. While it’s important to use caution when catching Error types, in these cases, it’s more about managing failure in a way that improves user experience and provides some level of recoverability rather than letting the application fail catastrophically without any trace what happened.
j
Most often in example Android world depending on third party libs like http clients its impossible predict all exception types. Do not want to crash an app because using an Android phone with invalid SSL handling, like Huawei or such. Often in those scenarios have no choice by catch all exception in network requests. I do not think want fail fast approach on that because users have bad software OS.
👍 1
👍🏻 1
t
Good article. I’m just confused that in the takeway it has:
If you must catch
Exception
, always rethrow it.
Shouldn’t this be
Throwable
? `Exception`s are the kind of errors you can “recover from”, right?!
👍 1
h
Great blog! Sadly, it doesn't have a feed I can subscribe to (RSS or Atom)…
k
There's a small typo: in a couple of places you've got "Something when wrong" instead of "...went...". Regarding the advice to log and rethrow, this is often considered an anti-pattern. SonarQube will flag it as a code smell. Generally, this is a useful article and an enjoyable read.
âś… 1
r
Log and rethrow generally results in noisy duplicate stacktraces, I hate it. Log when you handle.
âž• 5
c
@Stefan Oltmann Sorry for taking a long time to respond.
Catching Throwable around the main() method can be a good practice in certain scenarios, primarily because it ensures that any unexpected exception or error is logged, giving you a chance to analyze the failure later.
If your runtime is properly implemented, a throwable that bubbles up to the main method should already be logged somewhere by the JVM, so this adds no value. Even worse, it decreases the chances of getting useful information, because attempting to extract that information from within the process can strain it further when it is already dying. I've seen multiple times situations in which removing the global
try…catch
has increased the amount of available information available from within Kubernetes logs etc, or at the very least made it less noisy.
For instance, take UnsatisfiedLinkError. If a DLL fails to load, the default behavior would be for the program to crash. Instead of letting that happen, I prefer to catch this error and show a meaningful message to the user.
But you wouldn't implement this by having a
catch (e: Throwable)
at the root of the call stack, right? That's probably not where the DLL is loaded, so you probably have some kind of method somewhere that is responsible from attempting to load the DLL and switching to an alternate implementation if it isn't available. In that method, you know that the only error you can handle is
UnsatisfiedLinkError
, so you would specifically
catch (e: UnsatisfiedLinkError)
. I do think this is good practice. My blog post is specifically about catching
Throwable
directly, but I think catching a specific subtype of
Throwable
is good practice. If you have any idea of how I could make this clearer in the post, please don't hesitate to share.
There are also ways to handle an OutOfMemoryError gracefully. If the try block is carefully structured to manage memory resources, it’s possible to recover and allow the program to continue functioning in a degraded state.
Yes. But again, that part of the code will never be written as
catch (e: Throwable)
. It will be written as
catch (e: OutOfMemoryError)
, because it is able to handle specifically that. By being specific, it avoids all pitfalls I mentioned of dealing with
Throwable
: there is no risk of interrupting the JVM's
ThreadDeath
process, etc. I have a few examples of this myself where I have a high-level
catch (e: OutOfMemoryError)
that aggressively clears caches before retrying the operation.
@Tgo1014
Shouldn’t this be
Throwable
? `Exception`s are the kind of errors you can “recover from”, right?!
It would be nice if that was the case… But no, sadly, it's not possible to have a general handler even for
Exception
because there are exceptions you shouldn't catch. Most notably in this Slack, we would know about
CoroutineCancellationException
, which is a subtype of
IllegalStateException
. If you
catch (e: Exception)
or even
catch (e: IllegalStateException)
without rethrowing them, you are creating zombie coroutines. For this specific case, I recommend @Sam's blog: https://betterprogramming.pub/the-silent-killer-thats-crashing-your-coroutines-9171d1e8f79b
@hho Thanks! You're right, it would be better to have one. You can subscribe to https://gitlab.com/clovis-ai/website/-/issues/64 if you want to be notified when I get it working.
Log and rethrow generally results in noisy duplicate stacktraces, I hate it.
Note that this isn't because of rethrowing. It's because it's logging an exception when there is already a handler higher in the callstack that will already log it. I didn't consider this use-case in this article because it is clearly pointless and I haven't encountered it in the real world. I'll add a section to the article.
Added an example to describe why rethrow+log is a bad practice.
I rewrote the takeaway section to clarify everything based on your feedback. The article should be updated in a few minutes. Thanks!
❤️ 6
@hho Finally got it working! https://ivan.canet.dev/feed_rss_created.xml
h
@CLOVIS Awesome, thank you! Just added it to my feedreader
🙏 1
@CLOVIS Hm. Now I tried to catch up on some of your posts … and it seems the links to the posts are missing from the feed. Title, description and date are there, but no URLs. 🥺
c
@hho it seems to be fixed? đź‘€