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

Sdílet
Vložit
  • čas přidán 14. 04. 2024
  • 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

Komentáře • 333

  • @orterves
    @orterves Před 27 dny +138

    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 Před 27 dny +12

      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 Před 27 dny +22

      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 Před 27 dny +37

      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 Před 27 dny +13

      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 Před 27 dny +12

      @@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.

  • @BrankoDimitrijevic021
    @BrankoDimitrijevic021 Před 27 dny +15

    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 Před 26 dny +5

      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?

  • @brandonpearman9218
    @brandonpearman9218 Před 27 dny +85

    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 Před 27 dny +8

      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 Před 27 dny +1

      @@awmy3109 No you do not, its not pleasant to look at :D, unless you run a youtube channel mocking bad code possibly.

    • @davidmartensson273
      @davidmartensson273 Před 27 dny +2

      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 Před 27 dny +5

      @@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 Před 27 dny

      @@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.

  • @logantcooper6
    @logantcooper6 Před 27 dny +61

    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 Před 27 dny +5

      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 Před 27 dny +8

      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 Před 15 dny

      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 Před 27 dny +95

    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 Před 27 dny +9

      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 Před 27 dny

      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 Před 27 dny +11

      @@AhmadElkhoulyrecord can be inserted after you checked for its existence. So you need to write duplicate handler code anyway

    • @gileee
      @gileee Před 27 dny +2

      @@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 Před 27 dny +9

      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 Před 27 dny +12

    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 Před 27 dny +4

      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 Před 27 dny +4

      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 Před 26 dny

      @@orterves Not first class citizens, but you can use LanguageExt's Either Monad, and others. The linq query syntax is quite nice to use.

  • @E4est
    @E4est Před 27 dny +12

    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 Před 26 dny +1

      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 Před 24 dny

      Yup, pretty much this. Like everything else, it depends on what and how you want to do something depending on the case.

  • @TheMasonX23
    @TheMasonX23 Před 27 dny

    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!

  • @CabbageYe
    @CabbageYe Před 27 dny +44

    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 Před 27 dny +7

      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 Před 27 dny +1

      Well, that's what OneOf is, but with a Sum type to handle more cases than what a normal Result would

    • @eyeiaye
      @eyeiaye Před 27 dny +2

      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 Před 27 dny

      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.

    •  Před 27 dny

      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 🙂

  • @protox4
    @protox4 Před 27 dny +8

    Nick, BDN supports comparing multiple runtimes at once. You don't have to run each separately.

  • @lordmetzgermeister
    @lordmetzgermeister Před 27 dny +7

    definitely agree that exceptions are overused, but saying not to use them is an overstatement

    • @mkwpaul
      @mkwpaul Před 26 dny +1

      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 Před 22 dny

      Well, do you agree they are not unpredictable?

    • @mkwpaul
      @mkwpaul Před 21 dnem

      @@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.

  • @simonm97
    @simonm97 Před 27 dny +29

    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 Před 27 dny +4

      You'd be surprised

    • @simonm97
      @simonm97 Před 27 dny +7

      @@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 Před 27 dny +5

      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 Před 27 dny +3

      @@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 Před 27 dny +2

      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.

  • @daverayment
    @daverayment Před 27 dny +11

    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 Před 27 dny +2

      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 Před 27 dny

      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.

  • @daystar548
    @daystar548 Před 27 dny +12

    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  Před 27 dny +2

      Yeah Goland, Rust and many other languages have this baked in

    • @diadetediotedio6918
      @diadetediotedio6918 Před 27 dny +4

      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 Před 27 dny

      @@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 Před 27 dny +2

      @@TehKarmalizer In that case its at least a deliberate choice to not handle it :)

    • @Contradel
      @Contradel Před 27 dny

      ​@@diadetediotedio6918 I agree.
      Also you don't know what the error is/can be, especially not as it's often just returned further up.

  • @pauljacobson4832
    @pauljacobson4832 Před 27 dny +2

    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

  • @josephizang6187
    @josephizang6187 Před 27 dny +1

    A refresher would be great Nick. Love Dometrain. Haven't regretted buying any course so far.

  • @RohitMoni0
    @RohitMoni0 Před 25 dny

    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

  • @renatogolia211
    @renatogolia211 Před 26 dny +1

    I'd love a video where different results libraries are compared. OneOf, ErrorOr, language-ext and so on...

  • @IanHorwill
    @IanHorwill Před 27 dny +19

    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 Před 27 dny +1

      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 Před 27 dny +1

      @@gileee
      It is not the "reason for the existence of exceptions", from where did you got this?

    • @gileee
      @gileee Před 27 dny

      @@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 Před 27 dny +2

      @@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 Před 27 dny

      @@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.

  • @fusedqyou
    @fusedqyou Před 27 dny +36

    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 Před 27 dny +3

      They do happen often when say database providers return resource not found exceptions when doing data store queries.

    • @Denominus
      @Denominus Před 27 dny +2

      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 Před 27 dny +3

      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 Před 27 dny +1

      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 Před 27 dny +4

      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.

  • @DanielRuppert-xq4rz
    @DanielRuppert-xq4rz Před 27 dny

    Hey Nick, i really want to thank you for your content

  • @computer9764
    @computer9764 Před 27 dny

    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.

  • @mohitkumar-jv2bx
    @mohitkumar-jv2bx Před 27 dny +3

    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.

  • @Thorarin
    @Thorarin Před 27 dny +1

    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 😅

  • @jfftck
    @jfftck Před 27 dny +4

    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 Před 27 dny +4

      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 Před 27 dny +2

      @@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 Před 27 dny

      @@TehKarmalizer Those doing that are novices. Never met an experienced dev doing that. Honestly don't know where you guys meet such.

    • @davidmartensson273
      @davidmartensson273 Před 27 dny

      @@awmy3109 Seen enough of it from people you would think should know better so you probably have just been lucky then.

    • @jfftck
      @jfftck Před 27 dny +1

      @@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.

  • @OrionTheCookie
    @OrionTheCookie Před 27 dny

    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.

  • @iSoldat
    @iSoldat Před 27 dny

    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.

  • @Spartan322
    @Spartan322 Před 15 dny

    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.

  • @MrFreddao
    @MrFreddao Před 27 dny

    Very nice example! Thanks a lot my friend!

  • @elraito
    @elraito Před 26 dny

    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.

  • @bilalakil
    @bilalakil Před 25 dny

    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.

  • @HarshColby
    @HarshColby Před 27 dny +5

    Since exceptions should only be used for relatively rare events, the performance improvement isn't all that impactful.

  • @playwo9635
    @playwo9635 Před 27 dny

    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?

  • @algorithm-artisan
    @algorithm-artisan Před 26 dny

    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.

  • @msironen
    @msironen Před 27 dny

    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 Před 27 dny

      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 Před 27 dny

      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 Před 27 dny

      ​@@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 Před 27 dny

      ​@@gileeeTask.FromResult(new Some()) ???

  • @Hyp3rSon1X
    @Hyp3rSon1X Před 23 dny

    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

  • @sodreigor
    @sodreigor Před 27 dny

    Do you still use OneOf for Libs that you are going to make use in multiple projects?

  • @BloodHaZaRd666
    @BloodHaZaRd666 Před 27 dny

    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 Před 27 dny

      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.

  • @antonkomyshan1727
    @antonkomyshan1727 Před 27 dny +5

    No any explanations / deep dive / IL viewing what MS change to improve performance? 😢

    • @stefano_schmidt
      @stefano_schmidt Před 27 dny +1

      I've heard that they just removed a single "Thread.Sleep(time * 2)" line that they forgot to remove before

  • @CXCubeHD
    @CXCubeHD Před dnem

    Exceptions are exceptional, meaning when you create some kind of function that could throw an expected error, don't use exception

  • @obiwanjacobi
    @obiwanjacobi Před 27 dny +9

    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 Před 27 dny +2

      ["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 Před 27 dny +1

      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 Před 27 dny

      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 Před 27 dny

      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 Před 27 dny +1

      ​@@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.

  • @HeroicMaster
    @HeroicMaster Před 17 dny

    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.

  • @christophem6373
    @christophem6373 Před 24 dny

    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 ?
    ❤❤❤

  • @hektonian
    @hektonian Před 27 dny +1

    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?

  • @pauljohnsonbringbackdislik1469

    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 Před 25 dny

      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.

  • @GlassScissors
    @GlassScissors Před 23 dny

    Great video Nick, please give us more examples in the next video on the use in practice for OneOf.
    Thanks and cheers!

  • @StarfoxHUN
    @StarfoxHUN Před 27 dny +4

    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.

  • @gorkyrojas9346
    @gorkyrojas9346 Před dnem

    And how would you get that ExceptionMiddleware functionality with a Result / OneOf type ?

  • @iGexogen
    @iGexogen Před 27 dny +2

    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 Před 27 dny

      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 Před 27 dny

      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 Před 27 dny +1

      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 Před 27 dny

      @@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 Před 27 dny

      @@Tsunami14 So I can nest thousands of try/catch blocks and it will not affect performance until exception is really thrown?

  • @travisabrahamson8864
    @travisabrahamson8864 Před 27 dny +1

    This is why I tell people that exceptions are the most expensive way to handle knowable issues.

  • @marcusmajarra
    @marcusmajarra Před 27 dny +6

    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.

  • @venom_snake1984
    @venom_snake1984 Před 27 dny

    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 Před 26 dny

    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 Před 24 dny

      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.

  • @G41headache
    @G41headache Před 27 dny +1

    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.

  • @pauljohnsonbringbackdislik1469

    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  Před 27 dny +3

      Logging errors to console makes the benchmark useless because the writing is the most expensive operation and it load levels everything else

    • @pauljohnsonbringbackdislik1469
      @pauljohnsonbringbackdislik1469 Před 25 dny

      @@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.

  • @AndersBaumann
    @AndersBaumann Před 15 dny

    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.

  • @satyayuga0
    @satyayuga0 Před 27 dny +4

    I just use the result pattern. Problem solved

  • @lexer_
    @lexer_ Před 27 dny

    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.

  • @Chainerlt
    @Chainerlt Před 27 dny +16

    I'm waiting for a long time for C# to adopt error as a value pattern natively, probably not gonna happen.

    • @vargonian
      @vargonian Před 27 dny

      Is that what Nick’s alternative is? I’m actually confused now about what the recommended alternative to exceptions is.

    • @Nworthholf
      @Nworthholf Před 26 dny +1

      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

  • @BackwardsDaveTV
    @BackwardsDaveTV Před 27 dny

    Nice video :)

  • @hasmich
    @hasmich Před 26 dny +1

    4:48 How can you say memory allocation hasn't improved when there's clearly 1 byte gain?!? /me *proudly wearing idiotic comment cape*

  • @soonhongng7037
    @soonhongng7037 Před 27 dny

    I like the random number a lot, actually.

  • @nicolasmousserin9712
    @nicolasmousserin9712 Před 27 dny

    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):
    czcams.com/video/N9XTh3fLJVs/video.html
    Single MAUI course base price (11 days ago):
    czcams.com/video/N9XTh3fLJVs/video.html

  • @ethanr0x
    @ethanr0x Před 27 dny

    Let's go!

  • @sudsieskymo4287
    @sudsieskymo4287 Před 25 dny

    Error handling *within* a loop is not a gratuitous example. Test this when the loop is inside the try/catch, instead.

  • @CarlintVeld
    @CarlintVeld Před 27 dny +1

    Why are exceptions still so slow?

  • @awmy3109
    @awmy3109 Před 27 dny

    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.

  • @keke772
    @keke772 Před 27 dny

    What about creating 500 status code errors, we need to handle the exceptions so we return proper response

    • @tuckertcs
      @tuckertcs Před 27 dny

      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 Před 27 dny

      @@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 Před 24 dny

      @@keke772 Why? What message are you going to return. Just check in the client code if this is for a UI.

  • @neociber24
    @neociber24 Před 27 dny +1

    I glad people are moving to errors as values

    • @awmy3109
      @awmy3109 Před 27 dny +3

      Only dumbb programmers are doing that.

  • @greencol
    @greencol Před 27 dny

    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.

  • @klocugh12
    @klocugh12 Před 27 dny

    NaughtyRequesty sounds like it gets a lot of coaly.

  • @ScrotoTBaggins
    @ScrotoTBaggins Před 23 dny

    "Old .NET 8" he says
    Lol 🗿

  • @yannlarente7724
    @yannlarente7724 Před 27 dny +2

    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.

  • @mirkogeffken2290
    @mirkogeffken2290 Před 27 dny

    Exceptions are just that. Things that shouldn’t happen. They perform great when they don’t happen.

  • @user-yx8nj9mp4f
    @user-yx8nj9mp4f Před 27 dny +2

    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.

  • @ErazerPT
    @ErazerPT Před 27 dny +1

    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 Před 27 dny

      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 Před 27 dny

      @@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 Před 27 dny

      @@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 Před 27 dny

      @@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 Před 27 dny

      @@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.

  • @DanGolick
    @DanGolick Před 25 dny

    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!

  • @JerryNixon
    @JerryNixon Před 12 dny

    Nested method == Local method

  • @hhgforfhuv
    @hhgforfhuv Před 27 dny

    vote for video about ways how to deal with errors without exceptions

  • @Osirus1156
    @Osirus1156 Před 27 dny

    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.

  • @ali_randomNumberHere
    @ali_randomNumberHere Před 27 dny

    exceptions themselves are the issue, which could be simply solved by discriminated unions, like Result, Maybe, OneOf, Either..etc

  • @ziaulhasanhamim3931
    @ziaulhasanhamim3931 Před 27 dny +3

    Even if exception becomes faster than normal sequential code still don't use them for validation and other stuffs.

  • @MalClarke
    @MalClarke Před 27 dny +1

    Not impressive at all. How many exceptions would you need to throw to even notice this difference?

  • @user-dq7vo6dy7g
    @user-dq7vo6dy7g Před 27 dny +1

    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.

  • @thebitterbeginning
    @thebitterbeginning Před 27 dny

    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.

  • @phyyl
    @phyyl Před 27 dny +1

    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) }`!!

  • @jamlie977
    @jamlie977 Před 27 dny +3

    as a Go developer, errors as values are the best errors, throwing is bad

    • @lollol35
      @lollol35 Před 27 dny

      But the code is pretty ugly. :/

    • @jamlie977
      @jamlie977 Před 27 dny +1

      @@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 Před 27 dny +2

      @@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 Před 27 dny +1

      You don't have exceptions at all. And I bet everyone would use them in Go if you did.

    • @gileee
      @gileee Před 27 dny +1

      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.

  • @rolandbistrischi5178
    @rolandbistrischi5178 Před 13 hodinami

    Me who use .net 4.6.1 because i dont updateted

  • @Arcadenut1
    @Arcadenut1 Před 27 dny

    Nested Methods = Yuck.

  • @ChristianHowell
    @ChristianHowell Před 27 dny

    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 Před 27 dny +13

    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 Před 27 dny +1

      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 Před 27 dny +3

      Thank you!! I really think everybody forgets the point of Exceptions. They're not meant to happen in your code!

    • @Denominus
      @Denominus Před 27 dny +2

      (And Rust) But, forget railroad programming, just having errors (not exceptions) be obvious in function signatures would be nice.

    • @andreikniazev9407
      @andreikniazev9407 Před 27 dny +1

      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 Před 27 dny +5

      @@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 Před 25 dny +1

    please speak slowly... 🙂 thanks

  • @DevelTime
    @DevelTime Před 26 dny

    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.

  • @Max_Jacoby
    @Max_Jacoby Před 26 dny

    random.Next(1, 10) >= 5 is true around 56%

  • @xxXAsuraXxx
    @xxXAsuraXxx Před 25 dny

    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