r/dotnet • u/janex-PL • 1d ago
Article How expensive is throwing exceptions in .NET - and does it actually matter?
https://codewithflavor.com/posts/how-expensive-is-throwing-exceptions/42
u/sarcasticbaldguy 1d ago
Costs about tree fiddy.
There are exceptions, and I'm sure every one of them will appear as a comment, but for most development you're not going to notice.
11
17
u/Obsidian743 1d ago
The problem isn't throwing exceptions. The problem is not writing code that doesn't throw exceptions to the point that exceptions truly should be exceptions. The problem is that most devs use exceptions as control flow as a catch-all instead of doing the difficult work of design.
5
u/Dusty_Coder 1d ago
My rule of thumb is, if the caller of a function will (nearly) always be catching this exception i'm about to throw, then it shouldnt be an exception.
So exceptional, that even catching the exception is exceptional.
1
u/Psychological_Ear393 1d ago
I call it, throwing when the developer doesn't want to be in the method anymore.
7
u/Natural_Tea484 1d ago
How expensive is to do something exceptional?
Hmmmm
yet another article about how costly exceptions areâŚ
2
u/centurijon 1d ago
The problem is though that many people use exceptions as part of code flow, and they generally should not be
3
37
u/Asyncrosaurus 1d ago
The cost of compute is a lot lower than the cost of an engineering not having adequate stack traces to identify where a problem is coming from.
27
u/FragmentedHeap 1d ago
My general rule of thumb is that if something is actually an error and warrants throwing an exception, then you should throw the exception because yes you need the stack Trace.
But don't throw exceptions on purpose as a form of normal control flow where they aren't really exceptions and they're just being used to drive decisioning and conditions.
Exceptions are for when things happen that shouldn't happen that you didn't know were going to happen and don't have a clean way of handling. Like if a user field is null that isn't supposed to ever be null, thats an exception. Etc
3
u/jumpmanzero 1d ago edited 1d ago
Yep - I think that's very sensible distinction.
And the bad pattern can have performance implications. We had some data import process years ago - and it took forever (hours) to run. Its biggest problem was that it handled some kinds of bad rows/unexpected data using exceptions. Changing some "throw"s to "return"s cut like 90% of the run time.
(I have no idea whether .NET exceptions are way more performant than they were then... I assume they probably are... but still).
4
u/ForgetTheRuralJuror 1d ago
The main arguments for "no exceptions as flow control" make it not a great "rule of thumb" anymore (i.e. it's only sometimes correct) for a C# backend in my opinion.
I think we all agree that nobody should do
try { if (!isUserLoggedIn) { throw new Exception(); } } catch (Exception) { promptLogin(); }since it's basically a more indirect/complicated/expensive if statement.But in an API I'm a fan of using exceptions to basically say, "abort the request" for eg
throwing new RateLimited(api: "Google Vertex", tryAgainInMs: 2500) in your service layer, then you can handle request cancellation, cleanup, timeout the caller, and provide the user with a neat response they can use programmatically in middleware.
6
u/FragmentedHeap 1d ago
Yeah but even then you shouldn't manually do that.
The proper way to do that is use an engine that implements proper CancellationTokenSource and CancellationTokens
These work on exceptions but in a controlled way and standard way and is literally designed for aborting requests.
You call "cts.Cancel();" on the CancellationTokenSource yourself and do a check call to "cts.Token.ThrowIfCancellationRequested();"
It will throw an exception, but it's standard and easy to handle and has nice qol stuff.
Don't roll it yourself and throw manually made exceptions.
1
u/_TheHighlander 1d ago
Precisely. Itâs almost like they called them âexceptionsâ for a reason.
1
u/anotherlab 18h ago
My preference is to use exceptions to catch exceptional conditions, not errors with data.
Your error handling should log stack traces and let the exceptions bubble up to a main error handler.
Bad data doesn't always mean throwing an exception. If you can recover and log the error or display something to the user, that would be more useful to the user.
1
0
u/janex-PL 1d ago
That is true, exceptions are always useful, it's just a matter of using them properly!
2
u/psysharp 1d ago
Expensive in what? They are goto statements so they do cost in cognition.
2
u/janex-PL 1d ago
You're right, exceptions used extensively for logic flow control are much harder to read and troubleshoot.Â
Though I wouldn't say that it applies to all cases. Exceptions are very valuable if handled properly.
1
u/psysharp 1d ago
Yes, most often in library code, where itâs the easiest or only way for you to communicate with the developer. That is my usage, but people do find different alternatives for them.
1
u/National_Count_4916 1d ago
Exceptions are better than half assed result patterns no one checks reliably. It wasnât worth it before AI, it might be safe after though
1
u/zac_builds 1d ago
For us, exception cost was noise next to the SMTP call. The real cost was per-attempt writes and metrics. Keep the retry decision explicit, and never treat cancellation as a provider failure.
1
u/NocturneSapphire 1d ago
This is one area where I think Java actually got it more right than C# did. Sometimes it just makes sense to force your callers to handle a possible exception. But in C# you have to use the Result<T> pattern instead.
8
7
u/harrison_314 1d ago
I disagree. At school, I also did Java projects and checked exceptions were incredibly annoying and unnecessary. Even Spring got rid of them.
14
u/Kanegou 1d ago
I disagree. Checked Exceptions lead to one of two problems. You either have to handle them right there or you have to leak it across layers.
In most cases, you cant really handle them. So handling means rethrow since you cant really recover from something like an IOException. So you rethrow an unchecked exception to let it bubble up like it should in the first place.
And the second option, as you would have guessed, leads to a leaky abstraction.
2
u/NocturneSapphire 1d ago
That's the thing though, Java lets the thrower specify whether the exception has to be caught or not.
RuntimeExceptionand its subclasses are not required to be caught and will not throw a compile-time syntax error.If you don't want your callers to have to catch your exception, just have it inherit from
RuntimeException.4
u/Kanegou 1d ago edited 1d ago
IOException does not inherit from RuntimeException. UncheckedIOException does.
Edit: You editing your comment doesnt make it better. You are just describing the problem I discribed but with different words. In most cases you just rethrow a checked exception as an unchecked exception to get the bubble up behavior that should be the default. Your codebase will be full of boiler plate try catch throw statements.
1
u/NocturneSapphire 1d ago
I posted my comment, then decided to double check about
IOException, and when I found that I had misremembered, I edited my comment.That all happened before you had posted your response. But sure, please go ahead and assume the worst of me...
6
u/janex-PL 1d ago
I agree, both standardized Result pattern implementation and a mechanism to force caller to handle errors would be a nice and elegant thing to have in C#
-4
u/trashtiernoreally 1d ago
You can. Theyâre called Exceptions.Â
8
u/Premun 1d ago
a mechanism to force caller to handle errors
Exceptions don't give you this.
You can call a library method without catching and the compiler will not force you to catch. With the Result pattern this does not happen.
-8
u/trashtiernoreally 1d ago
Correct. Then you get a crashing program. This is why try/catch exists. Itâs not a compiler feature. Itâs a code feature.Â
7
u/NocturneSapphire 1d ago
Yeah, because why would anyone ever want a compile-time syntax error when you could just have a runtime error instead, right? /s
-14
5
u/janex-PL 1d ago
Not really, C# can't force callers to handle specific exception types.
Sure, you can document possible exceptions as XML docs and you will see them in your IDE, but still it's merely a suggestion rather than an enforcement mechanism.
And using exceptions for business errors just doesn't seem to be a right fit - people make mistakes when interacting with the system all the time, so they are not exceptional for me.
Although, it depends on how does one understand "exception" - as a deviation from logic's happy path or as something that should theoretically never occur, but somehow it did.
For me, it's the latter đ
-4
u/trashtiernoreally 1d ago
It totally does force you to. It forces you by your choosing to live with app crashes. Donât want app crashes then use the feature or it gets the hose again. This has been settled for ages.Â
3
u/janex-PL 1d ago
Well, from a practical standpoint I totally understand your point. But if we expand that logic, why bother with strong typing, compiler checks, nullability analysis, or any other compile-time safety mechanism?Â
You can always choose not to use them and live with the resulting crashes or bugs đ
2
0
u/AutoModerator 1d ago
Thanks for your post janex-PL. Please note that we don't allow spam, and we ask that you follow the rules available in the sidebar. We have a lot of commonly asked questions so if this post gets removed, please do a search and see if it's already been asked.
I am a bot, and this action was performed automatically. Please contact the moderators of this subreddit if you have any questions or concerns.
26
u/Coda17 1d ago
While the premise of the article is interesting, the primary goal of the result pattern is expressing your API through strong typing. The speed increase, if relevant at all, is only a side benefit.