.NET 9 Fixed Exceptions but Still Don’t Use Them

  Рет қаралды 36,816

Nick Chapsas

Nick Chapsas

16 күн бұрын

Until the 30th of April, use code BIRTHDAY40 for 40% off any course, BIRTHDAY20 for 20% off any bundle and BIRTHDAY15 for 15% off your first year of Dometrain Pro: bit.ly/4aUVR8l
Become a Patreon and get special perks: / nickchapsas
Hello, everybody, I'm Nick, and in this video I will show you how Exceptions got much faster in .NET 9 and explain why I still don't think that they are fast enough to make any sense to use on situations where people abuse them
Workshops: bit.ly/nickworkshops
Don't forget to comment, like and subscribe :)
Social Media:
Follow me on GitHub: github.com/Elfocrash
Follow me on Twitter: / nickchapsas
Connect on LinkedIn: / nick-chapsas
Keep coding merch: keepcoding.shop
#csharp #dotnet

Пікірлер: 329
@orterves
@orterves 15 күн бұрын
The main problem with exceptions isn't even the performance, it's that they are not visible in the definition - the fact that they can be thrown from anywhere anytime means you have to constantly have them in mind to handle, or not and let them pass through, but always with the risk of killing operations unnecessarily and unexpectedly
@Denominus
@Denominus 15 күн бұрын
Yes, no transparency from the outside of when something might blow up in your face, unless someone has been extremely diligent and documented it (which doesn't happen). And of course, the obligatory: "Exceptions are just expensive gotos".
@fusedqyou
@fusedqyou 15 күн бұрын
That's exactly the point. Exceptions short circuit your code because they are meant to indicate an issue. The only exception is Task cancellation, which is a single event. They provide helpful information on fixing the issue so they don't have to happen again. I get the idea many people forget the point of them.
@iGexogen
@iGexogen 15 күн бұрын
Java developers have ability to specify what exception can be thrown from method, and if it is not handled code will not compile. And you know what.....they hate it!)))
@Mazzulatore
@Mazzulatore 15 күн бұрын
I love checked exceptions (Java obviously). And please use exception instead polluting with conditional code based on return objects or return code. Use exception as 'exceptions' from the regular flow just as break and continue jump over the for loop
@iGexogen
@iGexogen 15 күн бұрын
@@Mazzulatore I didn't like them in past, but now when I've grown as developer and worked in large teams on many large projects I understand that clarity and strictness are blessing and really worth that excess typing.
@brandonpearman9218
@brandonpearman9218 15 күн бұрын
Exceptions are widely used because they short circuit the whole flow without having to do any checks else where in the code. They shouldn't be happening for half your calls, it should be more of an exception case. That performance diff is usually not a problem because most companies do not have the type of load that would cause issues. From my experience there are many many things that teams should look at before worrying about saving a millisecond per 1000 calls.
@awmy3109
@awmy3109 14 күн бұрын
Honestly don't know what code all these people that complain about performance of exceptions have been writing. Will love to see it 😂😂😂
@davidmartensson273
@davidmartensson273 14 күн бұрын
@@awmy3109 No you do not, its not pleasant to look at :D, unless you run a youtube channel mocking bad code possibly.
@davidmartensson273
@davidmartensson273 14 күн бұрын
I have seen many cases where exceptions are used wrongly as a means to convey that something could not complete. If it happens rarely enough AND is caught early enough it might not be a problem. BUT I have seen it used in cases where it might represent 1/20 or more of the calls, and I have seen cases where such a method is reused without catching the exception and having the exception travel up the call chain and break much higher up, making tracking down the problem more difficult, especially if the ones catching it is another team. Using something like OneOf makes it very clear that the method will return a failure state you are expected to handle, which in my opinion beats the performance issues as a reason to avoid using exceptions :)
@awmy3109
@awmy3109 14 күн бұрын
@@davidmartensson273 If the method you call returns OneOf and you also return OneOf to the method that calls that method, on and on like that. Will really love to see how such garbage is going to be managed and maintained. Exceptions have no significant performance impact if you know what you are doing. Whoever is saying it has significant performance issues is spewing BS in my opinion.
@davidmartensson273
@davidmartensson273 14 күн бұрын
@@awmy3109 Well, the point of OneOf is that it should be either handled directly in the caller or returned as is if that is applicable, not nested ;) But for that reason I also have started to use the TryABC syntax where you return true or false and have an out param for the result. Its super easy to just use an if statement or ternary to handle failures and you cannot cause the kind of nesting you mention. The benefit of OneOf is that you can return multiple states together with the result, and if using inheritance, different states can have different message types. Sure I do use exceptions but only when I aim for it to not really have to be used.
@BrankoDimitrijevic021
@BrankoDimitrijevic021 14 күн бұрын
This is a dangerous advice. The perf is an issue only if the "good" execution path is much less expensive than the "bad". This is essentially never the case if your "good"" path talks to the database - even the lightest query will be much more expensive than the exception. So if the attacker wants to overload your server, all they need to do is send "good" requests. Using exceptions for what they were meant to do - error handling - is perfectly fine in most situations.
@Ryuu-kun98
@Ryuu-kun98 14 күн бұрын
this advice has nothing to to with the "good" execution path. It shows that something like this can drastically improve performance on the "bad" path. Personally I think the most important aspect about using OneOf / Result is that you have to handle the "good" and the "bad" execution path explicitly. You cannot forget to handle invalid state. Handling an Exception is optional. Handling OneOf / Result is required. Also you did not explain why this advice would be dangerous. Would you care to explain?
@logantcooper6
@logantcooper6 14 күн бұрын
Exceptions are just dead simple to understand and implement in a global exception handler. Honestly i think its where you should start first and only move to Option types later if you need the xtra perf.
@orterves
@orterves 14 күн бұрын
In my opinion, Exceptions aren't simple - they just make code look simple by hiding complexity. Unfortunately Result types would need compiler support - probably including an operator for easily converting exceptions thrown from a method into a result at the call site - to make them the de facto choice in C#
@LCTesla
@LCTesla 14 күн бұрын
exactly, between all the alternatives shown to me, exceptions are my preferred option because they provide a unified, singular way to deal with unhappy flows. any other approach seems to either make you handle 95% of cases cleanly while turning the remainder into catastrophes that blast out of your result structure OR raise the need to put a verbose try-catch block on every level. I'll only avoid exceptions when the performance hit is significant.
@AndersBaumann
@AndersBaumann 3 күн бұрын
This might work in a small system. But in a large system all the unnecessary exceptions will flood the application monitoring and hide the real problems.
@shanehebert396
@shanehebert396 15 күн бұрын
I've seen lots of cases where people forget the meaning of the word "Exception" and have made exception pathways part of the main/happy-path pathways.
@AhmadElkhouly
@AhmadElkhouly 15 күн бұрын
I saw people use this approach: instead of checking if a record already exists in a database before inserting, they try to insert and catch the SqlException. If they got an exception they would try again but this time with an update operation instead of insert. This is a typical case of using exception to control the path of a program which is a bad practice as I understand.
@gileee
@gileee 15 күн бұрын
People keep repeating that like a mantra, but an Exception is everything exceptional. So everything that's not exactly perfect can be an exception. Want to update a user? Ok: 1. Do you have permission? No? UnauthorizedException 2. Is the request valid? No? ValidationExceotion 3. Is the user id present in the db? No? NotFoundException 4. Is the object concurrency token correct? No? OptimisticLockingException ... 5. Ok, user updated. The problem is that you could try solving some of these errors with a Result class, but then you reach new problems. Since these ErrorResults can be returned from any level of business logic not just one long function (and it can be many levels so you can't avoid both Result and Exceptions) your code gets polluted with "if err return err" which is the reason exceptions were invented in the first place. So code like that isn't needed. You still need the stack trace so Result implementations often have the previous Result inside of them, so you're not avoiding it, but now the stack trace is a bunch of sentences people put together instead of "error in ClassName.FunctionName at this line..." that exceptions generate automatically. Also, Results don't have native language support to help with these things (which would be nice, maybe something like a new return operator like yield that returns the result immediately if it's an error). And the biggest thing, you can still get exceptions both in your code from simple bugs, and also every library you use when anything wrong happens, so you still have to think about exceptions while also doing everything to avoid them. So you also get code like try... catch (Exception ex) return ex; Which is also not ideal. There's performance and explicit code benefits, but there's a reason everyone just used exceptions. And it's not just the fact functional programming isn't exactly perfect in C#.
@GirlAteDeath
@GirlAteDeath 15 күн бұрын
@@AhmadElkhoulyrecord can be inserted after you checked for its existence. So you need to write duplicate handler code anyway
@gileee
@gileee 15 күн бұрын
@@GirlAteDeath You could write an upsert procedure in your db so you only go to the db once and only have a single call in your code. But who wants that?
@user-dq7vo6dy7g
@user-dq7vo6dy7g 15 күн бұрын
This! Exception performance is not an issue for us. Exception happen when something goes terrible wrong and frankly in that case I don't care about performance any more.
@pablocom
@pablocom 14 күн бұрын
Exceptions actually provide the most value when you throw them farthest. Error results may make sense in some situations, but force every method in the stack to deal with the possibility that the call could return an error, therefore they force to decide what to do with that error inmediatly... Also, all the return types will have to be the discriminated union of ErrorOr... But I'm not sure, I really want to give error results a try on a big/complex system to see how it goes...
@evancombs5159
@evancombs5159 14 күн бұрын
Error results are great, but due to not having native support the implementation leaves a bit lacking which can make them feel cumbersome at the moment. Hopefully some day C# gets union types so it won't be so clunky.
@orterves
@orterves 14 күн бұрын
The Result type (or equivalent) are best when coupled with an operator that can simplify the propagation up the chain, like the Rust ? operator, or the F# let! notation with a Result computation expression, and when the compiler enforces checking the returned result and every path of the result when matching on the it (again, like with Rust and F#). Unfortunately those features are unlikely to become first-class features of C# any time soon
@BrunoJuchli
@BrunoJuchli 14 күн бұрын
@@orterves Not first class citizens, but you can use LanguageExt's Either Monad, and others. The linq query syntax is quite nice to use.
@lordmetzgermeister
@lordmetzgermeister 14 күн бұрын
definitely agree that exceptions are overused, but saying not to use them is an overstatement
@mkwpaul
@mkwpaul 13 күн бұрын
It's not an overstatement. It's an understatement if anything. Exceptions are worse than gotos. Exceptions are worse than null. They're completely unpredictable. They make it impossible to make any guarrantees. Event when you try to handle them the syntax is incredibly cumbersome and leads to people catching way more things than they intended too. They also encourage people to just consider the happy path and completely ignore any possible errors. Errors as Values are a better alternative 99.9% of the time. Not just for performance but just for retaining maintainability and sanity.
@verbroez712
@verbroez712 9 күн бұрын
Well, do you agree they are not unpredictable?
@mkwpaul
@mkwpaul 9 күн бұрын
@@verbroez712 They do have defined behavior so in an absolute sense they're predictable. On the other hand, pseudo random number generators are also technically predictable. So that means extremely little. In a practical sense Exceptions completely destroy the understandability of any given piece of code, because while their behavior is well defined, the endresult of throwing or catching exceptions can have wildely different consequenses. If you throw an exception, you don't know where, who, how or if at all it is caught. If open a try catch block you have a very, very limited understanding of what it might catch, unless you know every single line of code that might run within the context of that try catch block, which is frankly ridiculous, and potentially not even possible. If you call any method, you can't be sure that it might not throw an exception, again except if you know every single line of code that might run within that method and everything else called from it. People complain about null, but exceptions are so much worse its laughable.
@E4est
@E4est 14 күн бұрын
The reason why I prefer Exceptions over result types is the amount of extra work you put into validating result types in every layer of the called functions. When I actually want to abort an API endpoint, because the provided data makes no sense, I can just throw and get a StackTrace for my logging. In my experience, some things cannot be validated exclusively in the model and the reason for a similar failure can have slight differences in different scenarios. And as the name suggests, they should be Exceptions. That's also why I prefer the usage of the Single() and SingleOrDefault() LINQ methods over First() in a lot of scenarios, because in some cases I really want to rather let my code fail than get a wrong or inconsistent result. Seeing the actual compared impact like you show off in the video is mind blowing to me and is very important to keep in mind to stay educated. An excessive usage of Exceptions should still be avoided, but I would not avoid such a nifty language feature all together. It should stay an individual decision and not be generalized.
@davidmataviejo3313
@davidmataviejo3313 13 күн бұрын
You are all wrong. Exception are for unexpected behavior. By the other hand errors are expected and they should be passed to the end layer. Also do you know how singleOrDefaul works? You are going to be having performance issues.
@troncek
@troncek 12 күн бұрын
Yup, pretty much this. Like everything else, it depends on what and how you want to do something depending on the case.
@protox4
@protox4 15 күн бұрын
Nick, BDN supports comparing multiple runtimes at once. You don't have to run each separately.
@daystar548
@daystar548 15 күн бұрын
I mean, this is essentially what golang's standard is: req, err := DoSomeRequest(url) if err != nil { // Handle error } There's no exceptions outside of panics, and they mentioned performance reasons for making this change.
@nickchapsas
@nickchapsas 14 күн бұрын
Yeah Goland, Rust and many other languages have this baked in
@diadetediotedio6918
@diadetediotedio6918 14 күн бұрын
Go way of dealing with errors is kind of as bad as C# handling with exceptions, you still don't have compiler guarantees about if the errors are being checked or not.
@TehKarmalizer
@TehKarmalizer 14 күн бұрын
@@diadetediotedio6918 you don’t really have that in any language. In rust, you can simply unwrap and panic instead of checking. In the end, it’s always a choice to handle errors or let them kill your program.
@davidmartensson273
@davidmartensson273 14 күн бұрын
@@TehKarmalizer In that case its at least a deliberate choice to not handle it :)
@Contradel
@Contradel 14 күн бұрын
​@@diadetediotedio6918 I agree. Also you don't know what the error is/can be, especially not as it's often just returned further up.
@CabbageYe
@CabbageYe 15 күн бұрын
Idk why you would need the OneOf nuget. If you're not using exceptions you could just create a custom result class that has a success flag and a property that holds the object
@Tsunami14
@Tsunami14 15 күн бұрын
Imo, the nice thing with OneOf is that it helps communicate if the result states have been handled. Say you call a function that returns a OneOf. In order to use it, you then .Match() it to handle each of the possible options. And once that's done, you can just work with the Result directly (instead of OneOf), and send that directly up the call stack.
@victor1882
@victor1882 15 күн бұрын
Well, that's what OneOf is, but with a Sum type to handle more cases than what a normal Result would
@eyeiaye
@eyeiaye 14 күн бұрын
Sure, you could implement it however you want, and if you'd prefer to download as few packages as possible then that's fair enough. But what you have described is essentially just OneOf but with less functionality.
@davidmartensson273
@davidmartensson273 14 күн бұрын
If you use the pattern in many places in the code, just having OneOf will directly tell the user of the method that it will return a state together with the result. If you implement your own class you need to use naming rigorously to make sure to always know that your should handle the returned state. Its a way to make the intent more visible.
@AntonHolastarn
@AntonHolastarn 14 күн бұрын
Or a readonly record struct (or whatever really) as a base type with nested subtypes for the different cases. Then just switch on the type and you're set. I think I got that from Zoran Horvat, works great and really just n+3 lines somewhere so barely any extra work tbh 🙂
@simonm97
@simonm97 15 күн бұрын
The problem with the benchmark is that it doesn't really represent a real life usage of exceptions. While I agree that users could voluntarily spam the system to cause exceptions, there shouldn't be nowhere near 50% of requests causing exceptions.
@victor1882
@victor1882 14 күн бұрын
You'd be surprised
@simonm97
@simonm97 14 күн бұрын
@@victor1882 Why would I be surprised? I have eyes on a system in production and if I get 0.1% that's a lot
@davidmartensson273
@davidmartensson273 14 күн бұрын
Maybe, but with a speed difference of almost 1000 even 1/10 will cause a lot more performance cost and memory allocations, and once you start using exceptions for state, you might end up having multiple such nested in one call, I have seen such things in real code base, and then it will add up. It also as mentioned in another thread hides state because the method does not indicate it can throw an exception meaning the exception might end up way up the call chain in code written by someone with no idea about what the exception is. I always argue that exceptions should be used sparingly and never ever for things that are expected to occur. So no validation of user input should throw exception. Also they should be used mostly in cases where the caller can assume that the call will work.
@victor1882
@victor1882 14 күн бұрын
@@simonm97 I mean surprised by what people use exceptions for out there, from form validation to flow control, even Microsoft uses exceptions as URL navigation in Blazor
@davidesparzaguerrero4545
@davidesparzaguerrero4545 14 күн бұрын
Think on Unity and game programming, where some scripts are run multiple times... _per frame_! You could have hundreds of exceptions being thrown per second if they are carelessly used to represent deviations from the happy path rather than truly catastrophic situations.
@TheMasonX23
@TheMasonX23 14 күн бұрын
I took the Result class from your video and have extended it, including an Option type that can be implicitly converted back and forth, and they both support unwrapping for ease of use while still being more explicit about null returns than even nullable types. Very much inspired by Rust's types. Such a game changer, thank you for teaching me!
@josephizang6187
@josephizang6187 14 күн бұрын
A refresher would be great Nick. Love Dometrain. Haven't regretted buying any course so far.
@pauljacobson4832
@pauljacobson4832 14 күн бұрын
IT is like the symbiosis of nature, you can't have everything, if you make your life easier, it will cost you more resources, the important thing is to arrive and find the right balance, and to For me, the standard that exceptions represent for managing errors, and being able to type errors for each business case seems much more advantageous to me than more performance in a non-appy flow
@daverayment
@daverayment 15 күн бұрын
Sure, don't use exceptions for control flow, but they are still immensely useful if they are used as intended. I fear viewers may get the wrong impression from this video (and especially its thumbnail message to never use them). The example given in the video is intentionally a worst case scenario which should never occur in a real application. Again, although benchmarking is useful, exceptions have a very reasonable perf impact when compared to what they do behind the scenes. For the vast majority of users, the presented advice to use more complicated result return methods seems unwise. That's not to mention that you've lost advantages of exceptions, in that they naturally bubble up until they are handled and can contain nested info on problem causes, which is vital for logging etc. Use exceptions, but as with any feature, use them for their intended purpose and be aware of the alternatives for high-performance or custom scenarios. I would have loved to have seen a more positive video celebrating this perf win of .Net 9, possibly with a discussion of the low-level changes which led to the improvement.
@diadetediotedio6918
@diadetediotedio6918 14 күн бұрын
LOL, you say they have a very specific and special usecase, and then you just say they are useful and the performance impact do not matter compared of what they are doing. You understand that if the case is so rare and specific (and it indeed is), then there is no point discussing over the benefits of exceptions or the "complicated result return methods" (and calling them "complicated" is just unfair), right? There's no way he could possibly pass a "wrong impression" considering this.
@reikooters
@reikooters 14 күн бұрын
A few years ago when he made the last video on this topic, I felt like I was one of the only people in the comments that weren't using exceptions for control flow as he stated here. That's part of why he said many people are using them that way. And I've seen it in other developers code myself as well. Agree though that it would be interesting to see how MS achieved the improvement.
@HarshColby
@HarshColby 14 күн бұрын
Since exceptions should only be used for relatively rare events, the performance improvement isn't all that impactful.
@krccmsitp2884
@krccmsitp2884 14 күн бұрын
Don't forget the memory allocations.
@fusedqyou
@fusedqyou 15 күн бұрын
Why would Exception performance matter? Exceptions are not meant to happen at all, with the mild exception being cases such as Task cancellation. They don't happen often, nor are they meant to happen in general. If you are judging the performance of Exceptions or coming up with alternatives like OneOf you miss the point of Exceptions with their simplicity of delegating an error upwards so any code can catch it at a point where it can be gracefully handled. OneOf doesn't solve this issue as you will have to create some system where each method must now handle and return errors from some previous method by itself up until one can actually fix it. Can you see yourself writing a method that might return 10 different errors in its return type because the inner methods return 10 different errors? If somebody ends up needing to throw an Exception like this because their code might fail, then you filter them out before invoking the code. Bloating the code with OneOf is a bad solution if you ask me.
@jfpinero
@jfpinero 15 күн бұрын
They do happen often when say database providers return resource not found exceptions when doing data store queries.
@Denominus
@Denominus 15 күн бұрын
I agree you with you on the usage of exceptions, that they shouldn't happen often, and we can keep fighting that fight to stop people from using it for control flow and other incorrect usage. However, there is a "hole" in the language (and many other languages) where there isn't a nice way to deal with the possibility of a potentially successful response, or a non-exceptional failure, especially if that failure can be of many different types that the caller wants to be aware of. Then people turn to exceptions. Discriminated Unions/Sum Types are a good fit for this, if you have them available. The other problem is, exceptions do happen A LOT already. The framework throws exceptions like crazy for all sorts of non-exceptional stuff and libraries throw exceptions like crazy as well. Everything from authentication and cancellation to connection errors. They are splattered absolutely everywhere, its endemic in the ecosystem. There is nothing you can do about this at the application level except handle it. It also acts as a bad example to those who are trying to come up with their own error strategy. "Microsoft does it! Why can't I!". That said, I'm not a big fan of OneOf either, it creates its own problems. It's the best you can do in C# now, but it's still a very kludgy emulation of discriminated unions.
@leventegyorgydeak1300
@leventegyorgydeak1300 15 күн бұрын
You say "Exceptions are not meant to happen at all" (which I agree with) and then proceed to say you should also not use alternatives like OneOf. Well then how do you handle the validation failure of an input for example? You can't use exceptions for it, because it is "not meant to happen", and wrongly formatted input sure as hell will happen pretty often, maybe sometimes more often than correct input. You also say we should not use oneof, or alternatives to signal the failure of an input validation. You just use a bool and lose all the information about the failure? I don't think so. "Can you see yourself writing a method that might return 10 different errors in its return type because the inner methods return 10 different errors?" No, errors are cases which can never happen in a correctly working application (I think that is pretty much the definition of an error in software), so there is no point in signaling them in the return type, because you cannot meaningfully do anything with them aside from turning it into an error message for the user, you should just throw an exception. However, if e.g. a validation can fail for 10 different reasons, using a 10 type OneOf is much better than throwing an exception, but of course there are many ways to fix the 10-type problem (e. g. by creating an enum for the error type, or an interface depending on the exact error). I would still say there is a problem with OneOf bloating the code, but that is only present because of the limitations of C#, and hopefully we will get a fix (discriminated unions please). This is (1 reason) why I love rust
@Tsunami14
@Tsunami14 15 күн бұрын
I think that's what he means by "domain specific errors". i.e. use OneOf for things like duplicate/invalid email, and exceptions for things like timeouts and using disposed objects.
@diadetediotedio6918
@diadetediotedio6918 15 күн бұрын
Calling things you don't like 'bloat' is of no more value than not saying anything. You need to justify why is it a bloat if it solves a problem (and it indeed does) and it is inspired by how many modern languages handle errors and different return types. You don't know the discussion behind errors-as-values or checked-exceptions and is saying things here.
@RohitMoni0
@RohitMoni0 12 күн бұрын
Love that you added the third function to show how it 'should' be done. Would have been awesome to hear your thoughts on where exceptions *are* a good idea / the best way to do something
@mohitkumar-jv2bx
@mohitkumar-jv2bx 15 күн бұрын
This feels very similar to what rust does with "Result" Type, only that there the type is in the std library and the "match" is in the language reference. Pretty sure it is there in other languages too. and coming back to dotnet, I totally back this. And not just because of the performance reason(although that its one of the most important reason). Handling Exceptions/Errors as "values" makes the execution flow much more intuitive to reason about too. Nick i have seen your older video on the "OneOf", but a new video would also be really appreciated.
@renatogolia211
@renatogolia211 13 күн бұрын
I'd love a video where different results libraries are compared. OneOf, ErrorOr, language-ext and so on...
@christophem6373
@christophem6373 12 күн бұрын
What do you think about a video on dictionary subject ? 1. `Dictionary` 2. `ConcurrentDictionary` 3. `SortedDictionary` 4. `SortedList` 5. `ReadOnlyDictionary` 6. `ImmutableDictionary` 7. `ImmutableSortedDictionary` 8. HybridDic 9. ListDictionary 10. FrozenDic (since .NET 8) with use cases ? ❤❤❤
@antonkomyshan1727
@antonkomyshan1727 15 күн бұрын
No any explanations / deep dive / IL viewing what MS change to improve performance? 😢
@stefano_schmidt
@stefano_schmidt 14 күн бұрын
I've heard that they just removed a single "Thread.Sleep(time * 2)" line that they forgot to remove before
@MrFreddao
@MrFreddao 14 күн бұрын
Very nice example! Thanks a lot my friend!
@IanHorwill
@IanHorwill 15 күн бұрын
The point for me is to use exceptions for exceptional cases: something's happened that is not part of the normal flow. This of course requires judgement of what "normal" is, but validations are certainly a normal part of domain logic. An invalid or already-used email address (two different cases) should not be causing exceptions. I hadn't seen the OneOf type before but it's a nice tool to have available.
@gileee
@gileee 15 күн бұрын
If you want that you have to litter your code with the Result type and its handling. Which is usually superfluous and the reason for the existence of exceptions in the first place. Because a function can only return one thing (except exceptions that is).
@diadetediotedio6918
@diadetediotedio6918 14 күн бұрын
@@gileee It is not the "reason for the existence of exceptions", from where did you got this?
@gileee
@gileee 14 күн бұрын
@@diadetediotedio6918 Exceptions where created to remove the need for old c style code that would go something like: int resultCode = foo(&result); if (resultCode < 0) return resultCode; Then people invented exceptions so that the code would automatically unwind. The stack trace tells you the exact path, line of code to line of code, how the execution occurred before the exception. This then allowed for code like: auto result = foo(); Much simpler.
@davidmartensson273
@davidmartensson273 14 күн бұрын
@@gileee Absolutely not, the very name "Exception" tells you is not to be considered normal operation but something exceptional and preferably rare. Meaning anytime you know something can fail and that you know you will want to handle it, do not use exception but some other solution. Could be OneOf, you be a Try... syntaxt where the actual result is an out param and the return value is a success boolean, like TryParse for int's. There are many different ways to design the code to not need exceptions that are both more readable and clear and faster.
@gileee
@gileee 14 күн бұрын
@@davidmartensson273 Nope. I throw an exception whenever I stray from the path that's written down in the design document. The design document doesn't mention what to do when you try to update an entity that doesn't exist? Throw. It's that's easy. The exception goes all the way back to my single catch automatically and that's it. That's the point of exceptions, and the reason they were implemented.
@travisabrahamson8864
@travisabrahamson8864 14 күн бұрын
This is why I tell people that exceptions are the most expensive way to handle knowable issues.
@bilalakil
@bilalakil 12 күн бұрын
I'm curious what the performance will look like if you used exceptions with the `Result` approach (e.g. instead of try / catching the exceptions, you just return them in the result). It'll highlight how much the exception itself is the problem vs the try / catching.
@satyayuga0
@satyayuga0 14 күн бұрын
I just use the result pattern. Problem solved
@elraito
@elraito 14 күн бұрын
So how do you handle i/o like database connection interruptions or db errors? Geniunly curious because thats where i dont know a better way than to catching exceptions yet.
@DanielRuppert-xq4rz
@DanielRuppert-xq4rz 14 күн бұрын
Hey Nick, i really want to thank you for your content
@jfftck
@jfftck 15 күн бұрын
I would love C# to officially support changing all expectations into errors by value, so that handling errors is made clear by no longer allowing a whole block of code to be wrapped in a try/catch. See Rust or Zig to see how errors by value makes it clear when a function/method does throw errors and could even show unhandled errors in the editor, which is something that you can't do right now.
@awmy3109
@awmy3109 14 күн бұрын
Error by value is bad design. Whoever is pushing that nonsense doesn't understand that the stack strace is the most important part of exceptions.
@TehKarmalizer
@TehKarmalizer 14 күн бұрын
@@awmy3109 that seems like a conflation of errors vs exceptions to me. The term “panic” is more analogous to exceptions in some newer languages. Plenty of exceptions are thrown simply to pass the message and not for the stack trace.
@awmy3109
@awmy3109 14 күн бұрын
@@TehKarmalizer Those doing that are novices. Never met an experienced dev doing that. Honestly don't know where you guys meet such.
@davidmartensson273
@davidmartensson273 14 күн бұрын
@@awmy3109 Seen enough of it from people you would think should know better so you probably have just been lucky then.
@jfftck
@jfftck 14 күн бұрын
@@awmy3109 I can read stack traces very well, but there are many frameworks and libraries that have layers of indirection that cause issues with understanding the root cause. Also, with error by value, you are forced to handle errors directly instead of indirectly, so there is no need to use a memory wasting stack trace to get the same result of knowing the root cause. This is why the video talks about using a result instead of an exception, that stack is the root cause of memory usage and it doesn’t need to be there if you handle errors in place.
@sodreigor
@sodreigor 15 күн бұрын
Do you still use OneOf for Libs that you are going to make use in multiple projects?
@marcusmajarra
@marcusmajarra 14 күн бұрын
I'm not exactly sold on the proposed solution because it basically results in the same kind of code rigidity we see with checked exceptions in Java: the domain error cases become part of the API and every single caller is now forced to contend with this. And introduction of new possible domain errors force a chain of refactoring that goes all the way through until you reach the appropriate handler, which might not be the first caller to begin with. That being said, there is something to be said about trying to do away with the overhead incurred by exceptions and their implementations in terms of performance, but I feel like this suggestion is vastly incomplete as it doesn't provide advice as to how this change affects API, maintainability, and how error handling should be performed when you cannot rely on built-in mechanisms like catch/finally blocks.
@Spartan322
@Spartan322 2 күн бұрын
I kinda wonder if it would ever be possible for dotnet to just cheat with exceptions and avoid the stack unwinding via the compiler by functionally treating any method that throws exceptions without catching all of said exceptions as returning something akin to OneOf (would probably be more comparable to std::expected in C++) behind the user's back and all the try block does is evaluate the "underlying type" for the exception case and pass it off to a catch if any of the catches for each relevant type, else the function will return the new most common exception type. Sure its not a simple thing to implement, but neither is stack unwinding and doing that make exceptions just as efficient as the return type case, there are definitely things that need to be addressed in odd cases, but depending on how its implemented and how deep such a system would be placed it could go completely unnoticed except for having massive performance benefits. There were once talks on considering some type of manner to adopt this in C++, but those would take a decade before they see any proposal to the standard.
@G41headache
@G41headache 14 күн бұрын
It's no issue that exceptions are slow. Better yet, it incentives not abusing exceptions. Exceptions are there to crash early in order to prevent any collateral damage. If your application works properly, exceptions should never occur.
@rodrigojacques16
@rodrigojacques16 14 күн бұрын
Exceptions are super expensive unconditional jumps. If a method can fail in a controlled and predictable manner, I tend to use a result object to contain either the data or the errors.
@xxXAsuraXxx
@xxXAsuraXxx 13 күн бұрын
ALWAYS ALWAYS use Result pattern for if else check. Exceptions are to be used for unexpected errors that are not predictable. This is a junoir interview question
@Thorarin
@Thorarin 14 күн бұрын
I'm a little on the fence about OneOf and similar solutions. The Match method restructures code to be harder to read at times. The alternative (IsT1) also doesn't look very pretty. I'm a little afraid people will skip proper error checks as well, resulting in extra cryptic exceptions 😅
@BloodHaZaRd666
@BloodHaZaRd666 15 күн бұрын
Hello, So @Nick Chapsas : How is the best way to use exceptions on our programs. Because I m just exploring C# and some areas still dark :D thxx in advance
@leventegyorgydeak1300
@leventegyorgydeak1300 15 күн бұрын
My advice is: They should only be thrown when the application arrives at a state that should not be possible in a correctly working application. For example if you create a file and then read it immediately in another method, you should expect the file to be available at the path that you created it at. If not, that means the creation of the file was not correct, and there is a bug in the application, ergo that is an error, you should throw an exception.
@obiwanjacobi
@obiwanjacobi 14 күн бұрын
The Result pattern looks nice, but try to apply it to a real world scenario and your code explodes with error checks. For the Result pattern to be really effective we need some better (shorter) syntax. I personally think the 'don't use exceptions' is a case of oversimplification. Better perhaps to teach how to use exceptions 'correctly' because .NET == Exceptions, there is no getting around that. Also, most 'error handling' is not handling anything - logging is not handling. So only catch exceptions when you have something to add, like context or meaning (Exception type). I love the fact that for stuff that is beyond saving throwing an exception takes you out of the flow of execution without any effort or noise. I know this is one of the problems according to the Result fan-boys - "hard to reason about your code". It's not hard, you don't have to think about it at all. If the sh!t really hits thee fan, it just aborts - how cool is that!?
@diadetediotedio6918
@diadetediotedio6918 14 күн бұрын
["The Result pattern looks nice, but try to apply it to a real world scenario and your code explodes with error checks."] I don't get the "real world scenario". This kind of pattern is literally used everywhere, it is famous in FP and it is used in many .NET API's as well. You don't need to check everywhere, you can use monadic operations on these kinds of errors to pop them up and only deal with them on your prefered layer.
@victor1882
@victor1882 14 күн бұрын
It's not cool at all to not know what types of errors can be thrown unless you look at the source code
@evancombs5159
@evancombs5159 14 күн бұрын
The amount of code being written is not significantly different (i've checked). The difference is handling a result does not take you out of the flow of the code or add an additional tab to all of your code. It is just straight forward explicit code.
@igiona
@igiona 14 күн бұрын
All rust applications have to deal with that. There are number of real world apps written in Rust... The compiler will not easily let you go w/o handling all cases properly. Quite a pain, but indeed it's pretty cool to know that your sw cannot break, because you handled all the cases and the compiler does a damn good job in checking it. I hope this will be supported (not necessarily enforced) in c# as well one day ;)
@diadetediotedio6918
@diadetediotedio6918 14 күн бұрын
​@@igiona And in Rust you have lots of conveniences, like you can map ok results to others without needing to handle manually the results in the place (lifting up the error), and it is highly optimized for memory usage as well. I hope we get something along these lines.
@computer9764
@computer9764 15 күн бұрын
Nice. Exceptions are one of those things where defining what is 'exceptional' is difficult. Is stopping the world more efficient in the long run if it involves checking elsewhere and maybe not catching issues with different branches of logic? Maybe MS builds a web call to automatically throw exceptions when a non-200 code is returned even though if-modified-since returns a 304 You should definitely add a case where the exception was only fired once and see how the performance looks of just the try/catch wrapping with a valid exception case. I haven't ever looked into it.
@GlassScissors
@GlassScissors 11 күн бұрын
Great video Nick, please give us more examples in the next video on the use in practice for OneOf. Thanks and cheers!
@Hyp3rSon1X
@Hyp3rSon1X 11 күн бұрын
Does the performance impact come from exceptions being thrown? Or is it the overhead of using try-catch? It would be interesting to see a benchmark with 0 Exceptions thrown with one being ready to catch one, and the other having no try-catch. If the performance impact happens only if an exception actually gets thrown, I don't think that's that big of a problem... since an Exception being thrown should be... well the exception :D
@StarfoxHUN
@StarfoxHUN 15 күн бұрын
For me the key with exceptions is that they can centralize errorhandling whitout adding basically anything extra logic. Using this OneOf does faster but it looks like a pain to use, if i have to do this trought like a 3-4 level deep call. With exceptions i always has the try-catch at the entry point and that is all, the rest of the code is untouched. And even if i try to use as) little exception as possible, the try-catch still not avoidable especially if you are depending on external libraries which will most likely communicate with your code trought exceptions either way. Using it just feels like having a more complicated way to try to solve a problem that you still have to address to begin with. To be clear tought, the simplest validations, that most happens like at the entry point should not need to be done with an exception, it can be an instant return. Exceptions only helps anything if the problem happens not in the entry-point method.
@playwo9635
@playwo9635 15 күн бұрын
Totally agree with rarely using exceptions. Personally use them whenever I think a path is not expected to be hit or when I think a certain scenario has no graceful way of handling anyway. Am quite curious as to why execptions are so slow. Sure, it takes some time going up the callstack and finding the next catch, but why does that require 123kb of allocations?
@diadetediotedio6918
@diadetediotedio6918 15 күн бұрын
Because exceptions are objects.
@hektonian
@hektonian 15 күн бұрын
Rust has the right idea. In my opinion, exceptions are only good for fringe cases, result types (such as OneOf here) are the only correct way to handle errors, and it is a travesty that there is no "default" implementation for them. I will die on this hill, if need be. Like... If I have to throw an exception I feel like there's something wrong with the code. Must I really need to pollute the code with ugly try-catch blocks? I should know what the failure cases are, so why wouldn't I write a custom error type that simultaneously documents all the known cases instead of using a glorified goto -statement with extra data?
@CarlintVeld
@CarlintVeld 14 күн бұрын
Why are exceptions still so slow?
@OrionTheCookie
@OrionTheCookie 15 күн бұрын
I am still waiting for the Result to be GA. But maybe it's time to start using Result. These benchmarks are very convincing. I wonder if the same goes for when you program defensively against NullPointers with ThrowIfNullOrEmpty etc. And I fully agree with it being clearer to use OneOf or Result.
@HeroicMaster
@HeroicMaster 5 күн бұрын
Right now i kind of bite the bullet with exceptions. They help keep the code minimal and stop the execution when i want. I have a discord bot running on dotnet 8 and because theres so many layers and even ones from the nuget packages that it'd be a lot more to always keep implementing these returns and handlers rather than a middleman taking the info and giving responses from exceptions. When there's only 2-3 layers then it's not so bad not having exceptions as your main way for things like an API.
@iGexogen
@iGexogen 15 күн бұрын
Still no answers on my questions about exceptions that I was too lazy to figure out myself)) 1. Which action generates overhead? Constructing Exception object, or throwing it, or both are expensive? (Sometimes I pass around exception objects without throwing them only for use in is/as and inspection of contents, and want to know is it costy?) 2. Is try/catch block itself generates overhead if no exceptions are thrown in it? Can I feel free to wrap some code with this block, or it comes with some cost?
@diadetediotedio6918
@diadetediotedio6918 15 күн бұрын
It is the throwing + catching. The stack needs to be unwind and the control flow is restablished in the first catch there is.
@timseguine2
@timseguine2 15 күн бұрын
In theory there is nothing forcing exceptions to be slow. I am not entirely sure it all applies to the CLR (my experience in this regard is mostly related to C++), but generally the main reason why exceptions are slow is that the accepted "best" paradigm for exceptions that is used is the so-called zero-cost model. Which is called that because it is intended to have little to no cost in the happy path(to remove as many excuses as possible against people using them for error handling). It does this by taking every possible tradeoff to push any performance problems to the exceptional path. This typically means that the exceptional path dumps the processor into a state where the instruction and data cache are completely empty. Add to that that the stack unwinding is then done in an indirection heavy manner (because not doing so would incur nontrivial costs in the happy path), and you end up with several orders of magnitude slower performance in the exception path. Not only that, but it is often an amount of slowdown that is not particularly easy to predict.
@Tsunami14
@Tsunami14 15 күн бұрын
Haven't tested this, but my immediate guess is that a big part of the cost comes from generating the associated StackTrace each time an exception is thrown.
@diadetediotedio6918
@diadetediotedio6918 15 күн бұрын
@@timseguine2 You said there is nothing forcing exceptions to be slow, yet you said exactly why there are reasons for it to be this way. I don't think you can improve much on the performance of them while keeping the happy path "costless", you probably can deal with exceptions by converting them to be errors-as-values in the compiler (but then, you will need to do checked-exceptions, which I think is what swift does).
@iGexogen
@iGexogen 15 күн бұрын
@@Tsunami14 So I can nest thousands of try/catch blocks and it will not affect performance until exception is really thrown?
@awmy3109
@awmy3109 14 күн бұрын
Exception is the way to go to handle exceptional situations that should hardly occur if you know what you are doing. The stack trace is why exceptions are far better than the result pattern you are pushing and with exceptions you won't need if statements all over your code because they bubble up and you can handle all in one place if you want to. Never seen any dev in their right senses that just uses exceptions when events are the right thing to use.
@pauljohnsonbringbackdislik1469
@pauljohnsonbringbackdislik1469 13 күн бұрын
I realized I am strong user of the exceptions-based flow for 2 reasons. Most of the errors in my app originate from external services (e.g. Blob storage file access failure or name unique constraint triggered on an attempt to insert new records to the SQL database). The second reason is that I still rely on very simple validation (mostly MaxLength attribute) and these are handled by the built-in middleware for parsing DTO's from incoming JSON. And finally, as long as I fully control the only consumer of the API (i.e. frontend client) I don't think I will benefit from OneOf optimization anytime soon.
@pauljohnsonbringbackdislik1469
@pauljohnsonbringbackdislik1469 13 күн бұрын
And as much as I hate giving Microsoft any money for additional Azure resources, I believe cost evaluation would also be in favor of scaling up/out instead of putting developer time into subtle optimizations like this. I honestly think most people are better of with throwing exceptions, reducing cognitive load and keeping code easy to reason about.
@iSoldat
@iSoldat 15 күн бұрын
My goto phrase when writing code is "Exceptions are expensive". Unfortunately, the legacy code I work with has some of the worst practices regarding exceptions; cascading catches, with throw new... After being promoted to manager, I can now tell my reports to fix the code debt when they touch that code.
@lexer_
@lexer_ 14 күн бұрын
Go has problems but this is one thing Go got right. Explicit error passing instead of hidden control flow by throwing is just a the better solution.
@venom_snake1984
@venom_snake1984 14 күн бұрын
I am still using error code and signals, so I cannot say much about exceptions. Still, they can be helpful in understanding what went wrong with the code.
@uumlau
@uumlau 14 күн бұрын
The code smell for excessive Exceptions is the try-catch inside a loop, especially a loop of indeterminate size, moreso if there is a "new Exception()" line. If there is no try-catch, then that means any potential exceptions are unknown, and they should be allowed to bubble up to the top level where they get handled by logging and investigated. If there IS a try-catch, that means we know that Exceptions are possible, in which case we should strive to rewrite the code to fail gracefully in the known exception cases instead of try-catching them into oblivion. In some cases that rewrite isn't possible, and try-catch might be OK if handled with discretion. If the try-catch is in a loop, that's a significant anti-pattern in which we can potentially expect dozens if not hundreds or thousands or millions of Exception objects instantiated, which is exactly what Nick is showing us. This often causes a performance problem - in a real-life case, a loop of 3600 calls resulted in 3600 exceptions and added 20 seconds to the run time. The bigger problem is memory, especially if you're running in a small, light container, where garbage collection can't keep up with all the memory allocation.
@CabbageYe
@CabbageYe 11 күн бұрын
I disagree. If you're saving items to a database and you know the connection is shaky sometimes, having try catch in a loop makes sense. There are many other scenarios I can see it making sense.
@AndersBaumann
@AndersBaumann 2 күн бұрын
Developers that advocate for exceptions instead of Result for non-exceptional situations are obviously not working on large systems. In a large system all the unnecessary exceptions will hide the real problems. They will clutter the logs and the application monitoring will raise false positives.
@Chainerlt
@Chainerlt 15 күн бұрын
I'm waiting for a long time for C# to adopt error as a value pattern natively, probably not gonna happen.
@vargonian
@vargonian 14 күн бұрын
Is that what Nick’s alternative is? I’m actually confused now about what the recommended alternative to exceptions is.
@Nworthholf
@Nworthholf 14 күн бұрын
I hope with all the power of my soul that MS will stay reasonable enough to not give up to error code fanboys and will not effectively dismantle the type system just for some people to have fun with with neolithical style of error handling
@msironen
@msironen 15 күн бұрын
I tend to use tuples these days as return values for operations that can fail, such as Task DoSomething(). Maybe a bit crude compared to the OneOf library, but is directly supported by the language and I think it's rather readable (now that you can name the tuple members).
@Denominus
@Denominus 15 күн бұрын
There unfortunately isn't any way to guide the NRT analyzer with functions like that. So if you have a function that returns `Task`, you can't annotate that function to say "When Success true, Thing is not null", or "When Success false, Error is not null".. So you either need to ignore the warnings (we turn warnings into errors so they can't be ignored), splatter your code with bang! escape hatches (bad), or introduce a type to carry results which can be annotated.
@diadetediotedio6918
@diadetediotedio6918 15 күн бұрын
I think the problem of this is the fact that you add a scape hatch to the errors, where using something like OneOf (or a proper result type) forces you to check first.
@gileee
@gileee 14 күн бұрын
​@@Denominus There's also the problem with casting generic type arguments. Which is kinda annoying when you have a Task you can't return Task.FromResult(new Some) because the template arguments are different, even tho Some implements ISome. So you have to make the method async and await the Task.FromResult so the Some is cast into ISome first and then put inside a Task result. Note I just used FromResult as an example, you'd have this problem in general if you didn't want to use async-await in a intermediate/helper method. I feel this would be an issue everytime you use a tuple (int, Error) where Error is an abstract you extend into specific errors.
@fluffydoggo
@fluffydoggo 14 күн бұрын
​@@gileeeTask.FromResult(new Some()) ???
@hasmich
@hasmich 14 күн бұрын
4:48 How can you say memory allocation hasn't improved when there's clearly 1 byte gain?!? /me *proudly wearing idiotic comment cape*
@neociber24
@neociber24 15 күн бұрын
I glad people are moving to errors as values
@awmy3109
@awmy3109 14 күн бұрын
Only dumbb programmers are doing that.
@greencol
@greencol 14 күн бұрын
Generally i advise using Exceptions in truly exceptional circumstances, but it is a sliding scale rather than binary, so ultimately comes down to taste and judgement. Use the right tool for the job.
@pauljohnsonbringbackdislik1469
@pauljohnsonbringbackdislik1469 15 күн бұрын
I get nearly the same timings for Exceptions and OneOf... Allocation - same as on the demo. It might be a problem with sending "false" as an argument to method with no logic except single ternary expression. Oh.. and I log errors to console even if catched with non-throwing if statement. So it shows you gain speed improvements only because the faulty branch never executes. The ONLY improvements (that I see) are in allocation and it is not specific to .NET 9.
@nickchapsas
@nickchapsas 15 күн бұрын
Logging errors to console makes the benchmark useless because the writing is the most expensive operation and it load levels everything else
@pauljohnsonbringbackdislik1469
@pauljohnsonbringbackdislik1469 13 күн бұрын
@@nickchapsas I agree. In real life these events would rather be logged to a buffer and dispatched to the monitoring endpoint or file - less of an impact.
@soonhongng7037
@soonhongng7037 15 күн бұрын
I like the random number a lot, actually.
@sudsieskymo4287
@sudsieskymo4287 12 күн бұрын
Error handling *within* a loop is not a gratuitous example. Test this when the loop is inside the try/catch, instead.
@keke772
@keke772 14 күн бұрын
What about creating 500 status code errors, we need to handle the exceptions so we return proper response
@tuckertcs
@tuckertcs 14 күн бұрын
In this case, the API controller would match on any result/OneOf types to decide if it needs to send a 404 or 500 error.
@keke772
@keke772 14 күн бұрын
@@tuckertcs no I am talking about unhandled exceptions. You need to wrap everything on a try catch in order for the user to get a proper message back
@leerothman2715
@leerothman2715 11 күн бұрын
@@keke772 Why? What message are you going to return. Just check in the client code if this is for a UI.
@ScrotoTBaggins
@ScrotoTBaggins 10 күн бұрын
"Old .NET 8" he says Lol 🗿
@BackwardsDaveTV
@BackwardsDaveTV 15 күн бұрын
Nice video :)
@klocugh12
@klocugh12 15 күн бұрын
NaughtyRequesty sounds like it gets a lot of coaly.
@nicolasmousserin9712
@nicolasmousserin9712 14 күн бұрын
I appreciate your videos and the courses you offer. However, I’ve noticed something intriguing about the recent ‘massive promotion’. It appears that the ‘base price’ for both a regular course and a bundle has increased by 21% in just a couple of days. This means that the advertised 20% discount on a single course actually translates to a 27.4% discount when compared to the original price, at least 11 days ago. As for the bundle, the actual discount is a whopping 1% when compared to the original price, also 11 days ago. I happened to watch the ‘NET MAUI Community Standup’ live session, posted 11 days ago, where Brandon showcased his .NET MAUI courses on Dometrain. The differences in the ‘base prices’ were quite evident: Bundle base price of MAUI (11 days ago): kzbin.info/www/bejne/hGq7hZtpm7F9jNU Single MAUI course base price (11 days ago): kzbin.info/www/bejne/hGq7hZtpm7F9jNU
@ethanr0x
@ethanr0x 14 күн бұрын
Let's go!
@mirkogeffken2290
@mirkogeffken2290 14 күн бұрын
Exceptions are just that. Things that shouldn’t happen. They perform great when they don’t happen.
@hhgforfhuv
@hhgforfhuv 14 күн бұрын
vote for video about ways how to deal with errors without exceptions
@ziaulhasanhamim3931
@ziaulhasanhamim3931 15 күн бұрын
Even if exception becomes faster than normal sequential code still don't use them for validation and other stuffs.
@MalClarke
@MalClarke 14 күн бұрын
Not impressive at all. How many exceptions would you need to throw to even notice this difference?
@user-yx8nj9mp4f
@user-yx8nj9mp4f 14 күн бұрын
Misleading video title. Probably for clickbait. Misleading method names. A method that won't fail or fail actually performs a completely different function. In reality, one of the methods catches the exception, but the other does not. Using exceptions and catching them are completely different things. 0:30 "...they (exceptions) are totally suck... don`t use them." 1:55 "The best way to show you how bad exceptions." 4:00 Shows the overhead of catching exceptions, probably thinking it's proving a "problem" with exceptions. 5:00 Talks about the exception that is thrown when validating user data. In the loop from the test method, in addition to catching the exception, a request to the server is not created, as usually happens when validating user data. The overhead from catching an exception when validating user data is usually a small fraction of the overhead from sending a request to the server.
@DanGolick
@DanGolick 13 күн бұрын
Why are exceptions slow and use a lot of memory? Because they capture a stack trace. Why do they capture a stack trace? Because they are for debugging errors. Save them for truly exceptional behavior. They should not be thrown for application logic!
@yannlarente7724
@yannlarente7724 15 күн бұрын
I think Exceptions make for better code and I don't think it's realistic to edit all your application models to have an additional property that will inform higher level of an error. Then you have to add handling at all levels of the code ? To me Exceptions are perfectly good for Validation when most of your code should flow as expected. A Validation error should be an exceptional case in most cases. If you worry about user input spamming you with errors, then maybe you lack some Client-Side validation or spam control features. Because of that, I'm very happy to see some performance improvements to the Exceptions.
@ali_randomNumberHere
@ali_randomNumberHere 14 күн бұрын
exceptions themselves are the issue, which could be simply solved by discriminated unions, like Result, Maybe, OneOf, Either..etc
@user-dq7vo6dy7g
@user-dq7vo6dy7g 15 күн бұрын
Exception shouldn't happen. If they happen, something went terrible wrong. Our program logs a exception about every few days. Using some error return value would create so much boilerplate that is simply not justified. I really dislike this video. Dotnet uses a perfectly fine `bool trySomething(object parameter, out result)` pattern for many operations, that people should just apply to their own code when necessary.
@Osirus1156
@Osirus1156 14 күн бұрын
I still can't believe over all these years they are still throwing completely worthless null reference exceptions. Just tell me what object or property was null for the love of god.
@phyyl
@phyyl 14 күн бұрын
I can't wait for discriminated unions that will allow us to be more explicit about the return values in a simple, readable way and maintanable way. imagine `enum struct Option { None, Some(T) }` or `enum struct Result { Ok(TResult), Error(TError) }`!!
@ErazerPT
@ErazerPT 15 күн бұрын
Always been a pet peeve of mine. Exceptions are for EXCEPTIONAL circumstances. Like your drive died, someone ripped the cable, etc... Using exceptions for trivial error handling is like using your dentist as a toothbrush. Also, it breaks the "control flow", because you can't resume from point of exception. Sadly, quite a bit of stuff throws for no good reason other than they forgot, or couldn't care, to have return types with integrated error reporting so you end up with stupid amounts of try/catch blocks scattered around just so you can catch it and handle it in the "control flow".
@gileee
@gileee 15 күн бұрын
Everything that's not perfect is exceptional. Why would authorization failure throw an AuthorizationException otherwise. Why does the ValidationException exists in .NET and is thrown from the ObjectValidator. Because these are exceptional situations where any further processing can be thrown away and code rolled back automatically.
@ErazerPT
@ErazerPT 14 күн бұрын
@@gileee Incorrect. It's FLAWED. And neither exceptional nor exceptionally flawed. Just flawed. As for the why, it's simply because MS uses it willy nilly for no good reason. You think hitting the "Cancel" button, for example, is a good reason to throw? I could be snarky and say we're importing too many Python/JS users, but this has been going since way before that so no, it's not that.
@gileee
@gileee 14 күн бұрын
@@ErazerPT No, it's intended. Everything other than perfect is exceptional and that's how everyone uses it. Deal with it. Your definition is arbitrary, with unclear lines and rules. And also doesn't actually help with the most common bugs in code. How would avoiding exceptions help with a null pointer exception? Which as you might have seen makes up the vast majority of bugs in code (I don't actually remember the exact percentage or who did the math, Oracle I think). Also, the point of exceptions WAS to unwind code automatically to some set checkpoint. It doesn't break control flow at all. It was intended to streamline it by avoiding if (resultCode < 0) return resultCode. Which means you're free to focus on the perfect execution path and in the worst case the whole app crashes if there's a bug. Better that then the entirety of our data being corrupted because computation continued after an error because someone didn't return early.
@ErazerPT
@ErazerPT 14 күн бұрын
@@gileee From the dictionary : unusual; not typical. You think then that an ever present "Cancel" button in a certain UI component and a user clicking it is "unusual"? The null pointer example is a valid exception, not a frivolous use. So much so, it's not a generic exception in C#, but a ArgumentNullException, which is VERY explicit in the "why" it happened. And should it throw? Yes. Because it should have been checked BEFORE the call was made. And you might say "well, if you checked it before, it wouldn't throw" which is why it throws, it's forcing you to either check it or handle the exception. As Nick showed, the exception has high costs, the checking has negligible costs, you pick what you prefer. And the last argument is pure bs. If you don't handle the exception close to the site, you risk "bubbling up" to a point where you can't recover from it and you're already in a "half-state" situation, god help you... On one of our API's, every endpoint has a try/catch around it, for logging purposes. And people understand the comment on that logline, which translates to "if you see this, you probably fscked up", because bar a total system meltdown, it's NEVER supposed to end there, as the whole thing is built around types that DO HAVE error reporting provisions AND you're supposed to have handled it WAY before it reaches that point. Oh, and the guy that wrote the original had none of it. He focused on the perfect execution paths a lot. Very little error checking and even less useful logging so when things went South, it was "guess what went wrong" night for everyone else because he left before he had to deal with his own pile of manure...
@gileee
@gileee 14 күн бұрын
@@ErazerPT A user pressing cancel in Chrome will trigger the default cancelation token and throw a TaskCanceledException. Perfectly normal behavior. A user selecting cancel in the UI of an app could throw an exception, but usually you don't need to because a void return is often enough. Especially in like JS where you can avoid both exceptions and the Result type because you can return anything from anywhere. I never said NullPointerExcpetion is invalid, I asked you how would using a Result type for return prevent it. Now that's something that would actually make a huge difference in code quality. Oh and if every one of your endpoint has a try catch use a middleware. The exception has all the data you need. So do it at the top level and return a 500 after logging. In an API I don't see any point in catching any exceptions before the very end when the Response is being finalized, because how can you even recover from a bad request? Just return an error and the user goes again. Transactions will roll back automatically..., so why even catch anything.in the intermediate layers. You're going against the workflow exceptions put you in. Like I'm currently mostly working on a large ERP solution with 20 different projects, with many moving parts and annoying requirements, and I just did a find all "catch" and we have a grand total of 2.
@jamlie977
@jamlie977 15 күн бұрын
as a Go developer, errors as values are the best errors, throwing is bad
@lollol35
@lollol35 15 күн бұрын
But the code is pretty ugly. :/
@jamlie977
@jamlie977 15 күн бұрын
@@lollol35 what's pretty ugly? something, err := Something() if err != nil { return err } and try { var something = Something(); } catch (ExceptionType e) { //handle error } imo the throwing one is much uglier and results into more unreadable code
@lollol35
@lollol35 15 күн бұрын
@@jamlie977 I mostly just catch at the top level. Exceptions are only for when an operation cannot be completed. Now for Go, I find the code consisting of a lot of if err != nil, and I am reminded of the good old C++ days. These are not good memories. As someone said: "It is as if the designers of the Go language ignored all programming language innovations from the 90's and the 00's". Now, if it suits the task that your are doing, hey great. Always use the tool that makes the most sense.
@gileee
@gileee 15 күн бұрын
You don't have exceptions at all. And I bet everyone would use them in Go if you did.
@gileee
@gileee 15 күн бұрын
If your go code is "if err return err" then the equivalent code for exceptions would be "". Because they're passed to the caller anyway.
@thebitterbeginning
@thebitterbeginning 15 күн бұрын
I use Exceptions for exceptional scenarios. I avoid them for normal program flow (such as basic validation when it's a normal possibility that something is null, missing, etc.). I'm cautious about using them in looping scenarios. There is always a place for them...but lazy thinking and misunderstanding can lead to their abuse (or reliance in unnecessary situations), which can harm your application.
@Arcadenut1
@Arcadenut1 14 күн бұрын
Nested Methods = Yuck.
@ChristianHowell
@ChristianHowell 14 күн бұрын
I have NEVER liked throwing exceptions.. I always created a result object that can have an exception... It handles all external calls from remote APIs to local ones... Catch Exceptions, don't throw them...
@mightybobka
@mightybobka 15 күн бұрын
Use exceptions! Don't bring stupid things like railroad-programming to your C# code. These made special for languages with perverted exceptions, like erlang or Haskell. You'll save 1 ms on network requests, but you lose years debugging!
@devlife013
@devlife013 15 күн бұрын
In my opinion at first glance using Railway oriented programming might be difficult to understand, once you understand the procedure then it will avoid implementing God methods/classes and also as Nick said it will save your memory and so on. If you have any benchmark or any other details, I would be very happy if you share it! By the way, thanks Nick about the another amazing video.
@fusedqyou
@fusedqyou 15 күн бұрын
Thank you!! I really think everybody forgets the point of Exceptions. They're not meant to happen in your code!
@Denominus
@Denominus 15 күн бұрын
(And Rust) But, forget railroad programming, just having errors (not exceptions) be obvious in function signatures would be nice.
@andreikniazev9407
@andreikniazev9407 15 күн бұрын
Agree if you are not working on an app with strict performance requirements. Especially in a world of microservices. Sometimes, I have to jump between 20+ apps and don't want to see smart-ass code; I want exceptions with stack traces lol.
@fusedqyou
@fusedqyou 15 күн бұрын
@@devlife013 Why worry about memory or performance when Exceptions are not meant to trigger in the first place? They are fail safes and you fix them. If you worry so much about the performance of them then fix your code rather than introduce this bloat.
@AlbertoCatagni
@AlbertoCatagni 13 күн бұрын
please speak slowly... 🙂 thanks
@Max_Jacoby
@Max_Jacoby 14 күн бұрын
random.Next(1, 10) >= 5 is true around 56%
@DevelTime
@DevelTime 14 күн бұрын
I switched from exceptions some years ago (first using TryXXX pattern, then extended version returning error message, then I made my custom Result type) and now I use them as the name implies -- for exceptional cases.
The Pattern You MUST Learn in .NET
20:48
Nick Chapsas
Рет қаралды 71 М.
Don't throw exceptions in C#. Do this instead
18:13
Nick Chapsas
Рет қаралды 244 М.
Угадайте концовку😂
00:11
Poopigirl
Рет қаралды 4 МЛН
БРАВЛЕРЫ ОТОМСТИЛИ МАТЕРИ😬#shorts
00:26
Await Async Tasks Are Getting Awesome in .NET 9!
9:24
Nick Chapsas
Рет қаралды 78 М.
"Stop Using Properties in C#, Just Use Fields" | Code Cop #013
11:53
The New Collection Access Feature of C# 13
5:54
Nick Chapsas
Рет қаралды 26 М.
Unreal Engine 5.4 Sneak Peek | GDC 2024
29:55
Unreal Engine
Рет қаралды 608 М.
98% Cloud Cost Saved By Writing Our Own Database
21:45
ThePrimeTime
Рет қаралды 188 М.
The Future of Game Development
8:58
Brackeys
Рет қаралды 949 М.
Vercel Gave Up On Edge
17:50
Theo - t3․gg
Рет қаралды 91 М.
The Right Way to Write if Statements in C#
9:04
Nick Chapsas
Рет қаралды 41 М.