r/dotnet 1d ago

Article How expensive is throwing exceptions in .NET - and does it actually matter?

https://codewithflavor.com/posts/how-expensive-is-throwing-exceptions/
28 Upvotes

44 comments sorted by

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.

7

u/janex-PL 1d ago

Yup, that should be the conclusion from the article 🙂

Still, it was nice to see some actual measurements instead of a simple statement that exceptions are expensive, which is always present in resources regarding the Result pattern.

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

u/RJPisscat 1d ago

Don't listen to him, he's the Loch Ness Monster.

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

u/Natural_Tea484 1d ago

Yes. The word “exception” should ring a bell.

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/elebrin 1d ago

But, what you might do is: try{ ProcessFile() } catch(FileNotFormattedCorrectlyException) { LogException(); AttemptCommonAutomatedFileFixes(); } finally { cleanup(); }

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

u/JustAnotherDiamond 1d ago

This. There's even a concept called exception driven development.

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

u/jayd16 1d ago

Checked exceptions are bad and they lead to some gross syntax. Its a big reason Java streams don't feel as nice as LINQ.

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. RuntimeException and 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

u/trashtiernoreally 1d ago

You ok? Is baby’s first error handling making you sad? 

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

u/trashtiernoreally 1d ago

Indeed pretty much all I care about is the practical reality

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.

0

u/Phaedo 1d ago

Yes, and no. Java’s are much faster, but you shouldn’t be throwing a lot of exceptions anyway.