Why all your classes should be sealed by default in C#

Поділитися
Вставка
  • Опубліковано 29 вер 2024
  • Check out my courses: dometrain.com
    Become a Patreon and get source code access: / nickchapsas
    Hello everybody I'm Nick and in this video I will explain why you should be sealing all your C# classes by default. We will take a look at the functional aspect of the sealing feature and then take a look at the performance as well.
    Link to analyzer issue: github.com/dot...
    Don't forget to comment, like and subscribe :)
    Social Media:
    Follow me on GitHub: bit.ly/ChapsasG...
    Follow me on Twitter: bit.ly/ChapsasT...
    Connect on LinkedIn: bit.ly/ChapsasL...
    Keep coding merch: keepcoding.shop
    #csharp #dotnet

КОМЕНТАРІ • 383

  • @hichaeretaqua
    @hichaeretaqua 2 роки тому +21

    I solved this issue a long time ago by changing the class template in ReSharper/Rider to internal sealed. My goal was not to improve performance, but to not accidently exposing a API I don't indent to expose. It's nice to see that the performance is also benefiting from it.

    • @rezataba6204
      @rezataba6204 2 роки тому

      Nice

    • @Cameo221
      @Cameo221 Рік тому +1

      This is an awesome idea. I shall also do this too.

    • @ilh86
      @ilh86 Місяць тому

      If the C# design team believe it's a historic mistake that they cannot fix by changing the default behaviour then my first thought was why don't they just change the class template to stop it being as big a problem going forward?

  • @weekendrobot
    @weekendrobot 2 роки тому +15

    I hate this advice because I have managed to fix so many broken framework and library classes over the years by using inheritance. And entire avenue of bug fixing possibilities are quickly disappearing. These classes are not intended to be inherited and extended and these fixes are brittle but at least they're possible. I'd rather be able to work around an issue today and fix my workaround tomorrow than just be stuck.

    • @TehGM
      @TehGM 5 місяців тому +4

      I tend to say: a good quality of a library developer is to be aware that you might not think of what is needed NOW, but end users might come up with different ideas.
      I like this advice for non-library projects. It's like free gains, and you can always change it in your project. But a good library author will allow users to extend it however they see fit.

    • @pakvg85
      @pakvg85 4 місяці тому

      totally agree. this approach will make libraries unrepairable in the future.

    • @blo0m1985
      @blo0m1985 26 днів тому

      being so IQ 200, should not you contribute to those codebases instead of "fixing"?

    • @weekendrobot
      @weekendrobot 25 днів тому

      @@blo0m1985 could be closed source.

  • @Krilllind
    @Krilllind 2 роки тому +7

    In a comment I made on one of your previous videos, I mentioned the preferred "composition over inheritance" pattern and got so much pushback. Glad to see you mentioning this as well!

  • @Gioandgoose
    @Gioandgoose 9 місяців тому

    I like the numeric values you use as examples.

  • @silentdebugger
    @silentdebugger 2 роки тому +7

    I jumped in hoping for a great performance boost after sealing ~1800 classes in my project. Perf increased by 0.3% overall. So kind of a mixed bag... Ah well, thanks for covering the fundamentals

    • @PhilippLenssen
      @PhilippLenssen 2 роки тому +4

      Wouldn't the compiler optimization already know which classes aren't ever inherited in the project, thus quasi-seal them for the build?

  • @thomasschroter3802
    @thomasschroter3802 2 роки тому +1

    Yeah! Since I played along with Kotlin some years ago, I got used to sealing all my classes in c#.
    It is not only a question of performance but, first of all, good an robust design of my code.

  • @obiwanjacobi
    @obiwanjacobi 2 роки тому +4

    Change your class template in your IDE to include sealed by default (and make them internal while you're at it).

    • @wesplybon9510
      @wesplybon9510 2 роки тому +1

      Just keep an eye out when you do updates. I've made template changes in VS before and updates will wipe them out.

  • @debtpeon
    @debtpeon 2 роки тому +55

    This is not a "design flaw". This is a historical artifact of object oriented languages where classes are designed to be inherited by default. This also permit classes in libraries to be extended. Clearly over the years there's been a move away from object orientation with better methodologies of extending features. C# was based on Java and other OO languages at the time.

    • @rauberhotzenplotz7722
      @rauberhotzenplotz7722 2 роки тому +17

      Hmm, inheritable by default, but methods not virtual by default.

    • @matthewwood4756
      @matthewwood4756 2 роки тому +4

      @@rauberhotzenplotz7722 - “encapsulation” is still one the 3 benefits of OO though….that’s one of the points of inheriting non-virtual methods.

    • @timseguine2
      @timseguine2 2 роки тому +4

      @@matthewwood4756 You can accomplish pretty much anything that is achievable with inheritance with composition instead, and it is usually more flexible, cleaner, and separates concerns better without sacrificing encapsulation.

    • @matthewwood4756
      @matthewwood4756 2 роки тому +1

      @@timseguine2 - I’m not necessarily disagreeing with you, but using true OO principles of multiple inheritance, the same can easily be achieved that more readily/accurately “models” real-world problems/designs/solutions. “Composition” is the answer/pattern that has naturally evolved due the mainstream implementation/acceptance of single-inheritance languages/compilers.

    • @timseguine2
      @timseguine2 2 роки тому +3

      ​@@matthewwood4756 No. Classical OO often confuses the object hierarchies' isA relationship with the isA relationship of the thing they are modelling. These aren't in general the same relationship from a mathematical standpoint, so it doesn't make sense to model them like they are the same thing.
      The argument against inheritance comes historically from the Liskov Subsitution Principle and has absolutely nothing to do with single versus mutiple inheritance languages.
      Or put more charitably, you are reversing cause and effect
      Yes in languages with single inheritance there is additional motivation to favor composition over inheritance, but that was partially the motivation for them deciding to force single inheritance in the first place.

  • @votodymyro8530
    @votodymyro8530 Рік тому

    Apart from performance and clarity reasons, sealing the class which implements IDisposable saves you from not implementing dispose pattern

  • @AlFasGD
    @AlFasGD 2 роки тому +3

    6:10 it's easy to fall into a pit of misconception, so I'll drop my thoughts there
    Notice those ZeroMeasurement warnings down there, those say that method duration is too small to be taken into account, often times because the method is inlined and its execution takes virtually the same time as calling an empty method, meaning it's "the fastest you can get" when comparing vs calling a method. So it's not actually "38x" faster or "1000x" faster, it's "the fastest you can achieve".

    • @nickchapsas
      @nickchapsas  2 роки тому

      I had run to run variance between the executions so in some cases it was ZeroMeasurement and in some it wasn't so I left that comment out

    • @AlFasGD
      @AlFasGD 2 роки тому +2

      This is probably an effect of the methods not being correctly aligned for an ideal implicit inlining scenario, but either way if you do notice a zero measurement warning, you should assume that it's happening sometimes.
      Remember that given how inlining isn't perfect, were that same zero measurement warning to appear every single time, the performance could easily not be as high in as many as half the cases in a real world scenario. This is microbenchmarking and sets up and ideal scenario to juice out the maximum performance, isolating as many external variables as possible.
      TL;DR always worth noting that *even once* you get a zero measurement warning.

    • @gnack420
      @gnack420 2 роки тому

      @@AlFasGD obviously you're not wrong, and the information you've posted is super interesting to me so thank you! But I think the benchmarks here are just to show clearly that there IS a performance gain for zero cost, the video is explaining why sealed should be default and demonstrating that there is ANY performance improvement is a good enough argument to support that.

    • @AlFasGD
      @AlFasGD 2 роки тому

      @@gnack420 I agree but I also believe that it's generally good to perform a general fact check

  • @matthewdee6023
    @matthewdee6023 2 роки тому +1

    So I had a look as to WHY, and it's mainly because a call to a VLT can be being turned into a direct call by the compiler, which makes sense (still not idea why the 'is' and 'as' operators run faster though) [edit]Same idea, the runtime doesn't need to walk the inheritance hierarchy.[/edit]
    I suspect that this will have less of an impact if you have a deep inheritance tree with all of the leaf classes marked as sealed, because any method that at runtime can accept the base class will still have to do a lookup. That said, if people stick to composition > inheritance that shouldn't be an issue ;-)

    • @TheKevinKaimon
      @TheKevinKaimon 2 роки тому

      Interesting! Where could I find more info on the why?

    • @matthewdee6023
      @matthewdee6023 2 роки тому

      @@TheKevinKaimon It''s in the linked github issue :)

    • @ArrovsSpele
      @ArrovsSpele Рік тому

      Does compiler really can turn overriden and hidden functions with direct calls with ease? Or more advanced inheritance based trees are still at tables? I know that sealed in real life barely makes performace impact.

  • @vdrasutis
    @vdrasutis 2 роки тому

    Nice and short as always, great video

  • @dieter5220
    @dieter5220 2 роки тому +1

    As a Kotlin dev who has been dealing with libraries with insufficient extensibility, I have to disagree.
    If an open class does not have any sub-class, then it should be JIT's job to optimize it's virtual calls (devirtualization).

  • @LuigiTrabacchin
    @LuigiTrabacchin 2 роки тому +5

    I Think that with the new feature of C# "Extension everything" this could be adopted in very fast way

  • @DavidRosensteel
    @DavidRosensteel Рік тому

    I was a little skeptical. Inheritance is a big feature to make a general statement about throwing it away. But interfaces exist, so having most classes sealed and interfaces available could give the performance boost of sealed while allowing for people to make their own API compatible classes. The main concern is that if something is missed and there isn't an interface or some other way to customize that part of the API and the relevant class is sealed then some dev somewhere is gonna break out reflection and do some sketchy hacks to get around it.

  • @manmohanmundhraa3087
    @manmohanmundhraa3087 Рік тому

    Eye opening video. Is same is true for sealed method ?

  • @RC-1290
    @RC-1290 2 роки тому +1

    So... we're using OOP to extend things in a standard way. And then we need to make sure we apply a keyword by default to disable it, so we get some performance back. I see...

    • @davidparker5530
      @davidparker5530 2 роки тому +1

      Makes you wonder why these kinds of people would use a language with such features in the first place? What's next, disable the GC and make the user explicitly cleanup memory? Generics?! That adds calls to Activator.CreateInstance(), better to hack that off too. Why not just use a language like C++ to implement your tight loop / perf sensitive code and use C# for its great readability, code organization and connivence?

  • @Galakyllz
    @Galakyllz 2 роки тому +12

    Unfortunately, I disagree with your assessment that we should seal for performance reasons and to stop others from inheriting our public classes (even though we cannot imagine how/why they would want to do that). Why limit what other developers can do with our code? Internal classes? Fine. Public classes? Never. I don't know how someone else may want to expand on this code, so why would I arrogantly seal it?
    This is the one thing that has pissed me off in the past: I'm trying to setup tests around some process, I need an instance of this object, and boom, I cannot create an instance for testing purposes (by inheriting and mocking the properties/methods) because the class is sealed. Terrible.
    Both middle fingers to Microsoft for making some of their public classes sealed - hours wasted.

    • @nickchapsas
      @nickchapsas  2 роки тому +3

      That's fine we can disagree. I believe that it is up to the developer to writes the code to determine how that code should be used. If something isn't designed to be inherited then it should not be inheritable. Allowing for such things adds more things that you need to maintain even though you never intended for them to be maintained in that way. And I'm vert glad that Microsoft is heavily going forward with this. They ended up maintaining a lot of baggage because they didn't do it earlier.

    • @FudgeYeahLinusLAN
      @FudgeYeahLinusLAN 2 роки тому

      I limit what other developers can do with my code because other developers aren't as good as me. :)

  • @mdonatas
    @mdonatas 2 роки тому

    From time to time it happens that you want to bend some library to your will or to intercept some internal state (by assuming full responsibility that it could break in the future!) and usually it would be impossible with sealed by default. Strictly from a crafty developer UX perspective - I despise sealed classes. I vote - no :)

  • @wultyc
    @wultyc 2 роки тому

    It would be nice if the language did that by it self maybe during the lowering process (not sure if that would make sense at this step) or even better making it sealed by default and having a config on the build process to change the behavior

    • @paulkoopmans4620
      @paulkoopmans4620 2 роки тому

      they simply can not do that due to backwards compatibility. This is a long standing problem that affects anybody in software. For the dot net team it is no different than for yourself. As soon as you push something out the door, with focus on access levels, sealed or not, etc. your "customers" might be using your 'flaw'. Changing it is a breaking change.
      So the best they can do and have been doing for a while, is adding them as these checks and leave it up to you to treat them a certain way. Also the reason you should invest or use a proper IDE that makes you these suggestions for best practices.

    • @vasiliychernov2123
      @vasiliychernov2123 2 роки тому

      There may be a class in another compiled assembly inheriting from the given class in current assembly. It's possible that they're linked only in runtime, so there's no way to know at compile time if the given class actually doesn't have any inheritors even if it doesn't have any in current assembly.

    • @wultyc
      @wultyc 2 роки тому

      I understand you both points of view and I do agree. I was just saying that I would like to somehow have this as default behavior of the language

  • @TheAproeX
    @TheAproeX 2 роки тому +5

    Is the difference only measurable in newer versions of .NET? Or will it be worth sealing all classes in .NET Core 3.1 as well?

    • @nickchapsas
      @nickchapsas  2 роки тому +3

      They apply to .NET Core 3.1 too

    • @protox4
      @protox4 2 роки тому

      Even older than that, full framework can take advantage of converting virtual calls on a sealed class to direct calls.

    • @yuriihonchar9336
      @yuriihonchar9336 2 роки тому

      ​@@protox4 not really. The results on Full framework(.NET 4.8) show almost no difference between sealed and open classes

  • @clashclan4739
    @clashclan4739 2 роки тому +6

    Hi nick, pls consider design patterns also in upcoming videos. Mainly DDD and eventsourcing. And whats ur opinion on aggregate roots

    • @EmptyGlass99
      @EmptyGlass99 2 роки тому +1

      This is a C#/.NET channel - there are already plenty of good videos on design patterns.

    • @neociber24
      @neociber24 2 роки тому

      I think he did videos about that using MediatR

    • @thecodeman_
      @thecodeman_ 2 роки тому +2

      You have great videos on that topic - on Milan's channel ua-cam.com/users/MilanJovanovicTech

    • @clashclan4739
      @clashclan4739 2 роки тому +1

      @@thecodeman_ thank you 😊

  • @djupstaten2328
    @djupstaten2328 Рік тому

    It makes sense that classes with no Vtables by nature will have faster methods.

  • @MikeFrench
    @MikeFrench 2 роки тому

    Question I always asked is why the tooling, examples, compiler, whatever don’t do this by default?

  • @PeterOeC
    @PeterOeC 2 роки тому +2

    Hmm perhaps the .NET team could add the "Sealed" to all classes not extended at compile time (or making it an option when compiling). Then C# would get faster without having the developer needing to seal all not extended classes him/her self

    • @kylekeenan3485
      @kylekeenan3485 2 роки тому +1

      I understand why you would want this, but I am not sure we want a situation where changes are pushed out that could potentially break large amounts of existing code bases. Better to let the c# team focus on c# classes and let developers focus on their own.

  • @SergeiFedorov77
    @SergeiFedorov77 2 роки тому

    A beginner question: I have a Visual Studio project in .net core 3.1. Will these benefits apply for me in my .net core project?

  • @badm0us3
    @badm0us3 2 роки тому

    Hahaha 420. You and me have a lot more in common than just programming :)

  • @xVirtualMagicx
    @xVirtualMagicx 2 роки тому +1

    To deprive myself of the possibility to derive something just because it is a few nanoseconds faster, which is absolutely irrelevant for 99.99% of all applications is kind of stupid.

    • @nickchapsas
      @nickchapsas  2 роки тому

      Because sealing a class is a permanent action that can't be reversed

    • @xVirtualMagicx
      @xVirtualMagicx 2 роки тому

      @@nickchapsas To undo this, I have to touch the code again. Make a new build etc. Spontaneously deriving a class for reason X is then no longer possible. Ergo, the "profit" from sealing the class must at least correspond to the effort of "undoing". And in this case the profit is in most cases zero...

  • @lorddcee
    @lorddcee 2 роки тому

    Is there any performance gains in the regular .NET Framework? Say in the latest 4.8 version?

    • @nickchapsas
      @nickchapsas  2 роки тому

      Yes

    • @lorddcee
      @lorddcee 2 роки тому

      @@nickchapsas Do you know if it's about the same amplitude?

  • @watherby29
    @watherby29 2 роки тому

    Since .net assemblys can be so easily decimpiled,what's the point. By easily I mean there are tools for it

    • @nickchapsas
      @nickchapsas  2 роки тому +1

      What does that have to do with anything in this video?

  • @mihcom123
    @mihcom123 2 роки тому

    Can't we have an option for the compiler to automatically add sealed keyword to all internal classes with no inheritors?

    • @nickchapsas
      @nickchapsas  2 роки тому +1

      You can make an analyzer that includes a refactoring. They might add the refactoring in .NET 7

  • @hano2424
    @hano2424 2 роки тому

    soft soft by Image-Line Software

  • @preservedmoose
    @preservedmoose 2 роки тому

    What about unit test frameworks? They use this for mocks.

    • @nickchapsas
      @nickchapsas  2 роки тому

      Mocks are based largely on interfaces and abstract classes. You can't seal and abstract class or an interface

    • @gnack420
      @gnack420 2 роки тому

      You should be injecting interfaces, not concrete types, where possible. Then you can always mock.

  • @tanglesites
    @tanglesites 2 роки тому

    Is this unique to .NET 7, or do you think the results would be similar .NET Core 6?

    • @nickchapsas
      @nickchapsas  2 роки тому +1

      It's been there since forever

  • @dmitrykim3096
    @dmitrykim3096 2 роки тому

    C# is a Java prodigy and Java is not about performance

  • @MHjort9
    @MHjort9 2 роки тому +173

    These kinds of easy optimization tips is my favorite type of content from you Nick.
    Making the world a more informed place, 0.2239ns at a time

    • @davidparker5530
      @davidparker5530 2 роки тому +9

      This doesn't make any sense 0.2239ns is essentially the time it takes to execute a single clock cycle on a 4Ghz processor. That's hardly enough time to even execute the return instruction. Aside from the suspicious benchmark numbers, all this optimization boils down to is removing the indirect call of looking up a virtual function address in the classes vtable and replacing it with a direct call instruction. At that point just make the method static / create a free function and you get the same effect.

    • @anderskehlet4196
      @anderskehlet4196 2 роки тому +1

      @@davidparker5530 - we have instance members for a reason. Getting the performance of static without changing the code seems like a good deal.

    • @davidparker5530
      @davidparker5530 Рік тому +3

      @@anderskehlet4196 "performance" will be relative and YMMV. If you have a function that does some heavy computation, the overhead of a call vs indirect call won't matter at all (we're talking about a ns or two savings...). It makes no sense to just blindly seal all your classes for "performance". Take any real class that does something useful and seal it and measure how you get no real world performance benefit from it, this whole video is just a contrived example with a poor benchmarking setup.

    • @RiversJ
      @RiversJ Рік тому +2

      @davidparker5530 That's a bit short sighted in my opinion, obviously in the grand scheme of things one shouldn't chase tiny improvements, but the relative difference is key here, if you implement this in all hotpaths in the application the change is rather dramatic and you won't even need a benchmarker to see itz you can see it with your own wet eyes. There are lots of places where C# is applied and Is performance sensitive. Try what happens when you're iterating stays in the teens of thousands with sealed vs open, it's huge for very tiny effort. Just write one more word!

  • @stephaniewallace311
    @stephaniewallace311 2 роки тому +122

    Praise from a random viewer: I’m very much a reader, and if I expect an article and land on a video, I’ve already hit the back button. Your videos are not only excellent enough to transcend my prejudices, but to provide some income with perks as well. Many thanks from an internet stranger for your fantastic work.

    • @mattshu
      @mattshu 2 роки тому +3

      I’m so the opposite and wish that could change lol (regarding the first part. love these videos)

  • @JosifovGjorgi
    @JosifovGjorgi 2 роки тому +4

    Like every advice from every "guru", sealed classes in every language are usable in small number of use-cases.
    If you can't inherit a class then every framework that is depending on proxy design pattern (for creating "sugar" classes) will fail and the list of frameworks is very large RestControllers, ORMs, DI etc.
    And why those framework will fail ?
    Because all of them depend on proxy design pattern, which can be implemented in three ways
    1. as a pair (interface and class) or
    2. as inheritance of the class annotated with metainformation.
    3. provide factory methods for every sealed class, that will be use by the frameworks (mostly use in DI)
    If you are using sealed then you must 1 or 3
    This means every seal class needs to have "dummy" interface in order for the framework A to create "the sugar" sealed class or factory method
    Congratulations, instead of one "sugar" class A, know you have sealed one "sugar" class A + dummy interface IA / factory method and your code base is now twice as big.
    Don't get me started on ORMs, there is a high change that the amount of SQL generation will be double or you will wonder why ORM always generates insert statements.
    But this is just the software developer perspective
    From library POV - in order to fight sealed word, the libraries have to provide compiler hooks and now instead of Microsoft or your fav language company you have to wait 3-rd party company to fix your compiler bugs
    Classes shouldn't be sealed by default, because they are almost always useless

    • @nickchapsas
      @nickchapsas  2 роки тому +1

      Everything you said can be done with interfaces and composition in C# :)

    • @JosifovGjorgi
      @JosifovGjorgi 2 роки тому

      @@nickchapsas yes
      However,
      if project with unsealed classes has 1000 classes
      then project with sealed classes will be at least 2000 classes
      And that is the price to pay for using sealed keyword by default

  • @arekxv
    @arekxv 2 роки тому +4

    Please avoid doing this for libraries. This is all nice and fine on paper, but if you seal a class in your library and I am using it and you haven't done something that I need, I have no way of overriding your classes to implement my behavior. You do not have a crystal ball to know how people are going to use your library, and people do not have weeks or even months of them begging you to implement a new feature / fix just so it fixes one main problem for them that you didn't think of.

    • @nickchapsas
      @nickchapsas  2 роки тому +1

      Libraries is where you MUST do it

    • @TheOmilis
      @TheOmilis 2 роки тому +1

      @@nickchapsas But how would you solve the problem when you need to change a behavior of a class just a bit? Overriding a method is often the only option to achieve something. In past I had to copy&paste the source code of an entire class just to change a few things because the method that I needed to change wasn't virtual (and the behavior was essentially hardwired). This would make this problem even more prevalent.
      I understand your point at this makes it easy to maintain the library but it also makes it a less useful, because if it doesn't allow me to change something, I can't use it at all.
      Ideally libraries would provide extension point for everything but that is rarely the case.

  • @briansandberg8229
    @briansandberg8229 2 роки тому +12

    You'd think the runtime could handle this. The jitter knows if any classes inherit from this one, and if additional assemblies are loaded at runtime then the affected code could be re-jitted.

    • @ZintomV1
      @ZintomV1 Рік тому +1

      It probably wouldn't be a good idea to run this at JIT due to the performance impact of that analysis. Much better to evaluate at compile-time and seal all classes without members that inherit them.

    • @smathlax
      @smathlax 5 місяців тому

      ​@@ZintomV1 You can't evaluate that at compile time because you don't know if an external assembly is inheriting from that class.

  • @Andruuid
    @Andruuid 2 роки тому +6

    The Microsoft Documentation from April 2022 says: DO NOT seal classes without having a good reason to do so.
    "Sealing a class because you cannot think of an extensibility scenario is not a good reason. Framework users like to inherit from classes for various non-obvious reasons, like adding convenience members. See Unsealed Classes for examples of non-obvious reasons users want to inherit from a type. ..."
    Also Mocking is a Problem.... thoughts?

    • @nickchapsas
      @nickchapsas  2 роки тому

      I clearly disagree with that as well as many developers in the C# and .NET team. You can clearly see that MS themselves don't follow that rule. Docs advice is designed to be beginner friendly. There are tons of advice in there I disagree with.

    • @Andruuid
      @Andruuid 2 роки тому

      @@nickchapsas Ok Thanks!, I actually think the same

    • @paulkoopmans4620
      @paulkoopmans4620 2 роки тому

      You do have an option to 'extend' sealed classes. You can do it with extension methods!
      The same article you are referring to though also ends with: "Portions (C) 2005, 2009 Microsoft Corporation. All rights reserved." and comes out of a book "Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries, 2nd Edition", Published Oct 22, 2008.
      We are back to that since 2000 to 2010.... the developer landscape has changed significantly and this is just one of many 'viewpoints' that have changed/shifted.
      There is definitely a big issues too with not sealing your types. Because it implicitly means that you as a developer, especially if you write a library, would have to put a lot of defensive code in to ensure that outside users implement the types different or wrong.
      Personally I also favour using extension methods even on types that are inheritable if possible of course. If I just need to add a helper, like addind an AddRange() or some display or factory method or something. Rather then to deal with the inheritance and having to implement then everything the thing needs to have.
      I always have to think back to one time I had to do it, having to add a helper to a certain type. I had to do it by inheritance but due to other bad design practices by the api designer, I was forced to implement 30 other methods.

    • @bass-tones
      @bass-tones 2 роки тому +1

      @@paulkoopmans4620 Extension methods currently have a ton of limitations though. For example, you cannot do something as basic as adding a property to a class using extension methods.
      Yes perhaps this is eventually coming but it’s probably at least 2 years out from being included in the language.

    • @paulkoopmans4620
      @paulkoopmans4620 2 роки тому

      @@bass-tones Yes I understand that extension methods are only able to do anything with the object by using its public interface. The name 'extension method' is a bit deceiving and I realize I am actually not 'extending'. The class does not change by creating extension methods.
      A sealed class though, which this topic is all about, will never be able to get any extension whatsoever, but at least you can add some helpers like maybe an AddRange() method that calls the single Add() method provided by the library. Or maybe a Search() or ToEnumerable().
      This is also still where encapsulation might also help you out, IF and ONLY IF the designer of a library actually has done it properly and depends on interfaces.
      If you ever wrote an external facing api (not webapi, but as a library I mean) then you know why you would try to make pretty much everything internal and the stuff that is public you very likely want to seal. The actual classes, from a library perspective, that NEED TO BE extendible by inheritance as the only option in order to be useful to the user, is probably near zero.
      Sealing your classes and guarantee yourself that your classes do 'exactly' what you expect them to do far outweighs the pain, risk and cumbersomeness that you would have to add if you leave your classes open for inheritance and your code consuming then would have to have all kinds of defensive code and checks in them.

  • @madcroc111
    @madcroc111 2 роки тому +10

    Sealed can be very annoying too. Like when you want to modify third parties code. Extend it and modify one function you want. With composition you cannot input it into functions that take the original class, only that take an interface, so you have to copy all the functions too that take or depend on original class.

    • @ashlar64
      @ashlar64 2 роки тому +1

      Exactly....it's happened to me a few times.

    • @MoireFly
      @MoireFly Рік тому +1

      That's a feature, not a bug. You're going to be doing that so so much more rarely than actually working on a normal class. Allowing instance means that normal code now needs to maintain invariants even in the face of fairly hard to predict code replacement. Your subclass needs to be tightly coupled with the base class, and needs to understand what the actual class internal api is, because if the base class ever changes anything, you're likely to encounter all those hidden assumption on a bug report.
      The effort of rarely copying a few method declarations is so much smaller than the effort of dealing with unnecessarily flexible code, especially if anyone was ever so unwise as to abuse that flexibility.
      Inheritance as a form of method interception is a recipe for unmaintainable spaghetti code.

  • @ristopaasivirta9770
    @ristopaasivirta9770 2 роки тому +42

    I'm curious if this has any effect after the code is converted using IL2CPP as is often the case when making final builds on Unity.
    Really interesting and awesome never the less!

    • @SunSailor
      @SunSailor 2 роки тому +3

      I even wonder, if this is the case for Mono in the first place.

    • @piotrzdanowski5873
      @piotrzdanowski5873 2 роки тому +6

      tactical dot in case someone will be less lazy than me and tests it: .

    • @Xankill3r
      @Xankill3r 2 роки тому +11

      Basically no difference in 2021 LTS as the .Net versions supported are Standard 2.1 and .Net 4.0. Neither of those have the specific optimization being talked here in the IL (using direct call instead of callvirt).

    • @SunSailor
      @SunSailor 2 роки тому +2

      @@Xankill3r Thank you for pointing out! Makes sense.

    • @ristopaasivirta9770
      @ristopaasivirta9770 2 роки тому +2

      @@Xankill3r Thanks!

  • @mihaimyh
    @mihaimyh 2 роки тому +3

    Where do you got .NET7-RC2, on the download page I see the latest preview7 as the latest available for download?

    • @phizc
      @phizc 2 роки тому +1

      Same here. I was going to make the same comment, but I'll stick it here and hope YT notifies me too if you get an answer 😉.

    • @g11a
      @g11a 2 роки тому +1

      +1: Where do people get RC1/2 from?

    • @kabal911
      @kabal911 2 роки тому

      Came to ask the same thing

  • @kuljok
    @kuljok 2 роки тому +8

    Hey Nick
    I'd like to say thanks for your video and I have a question. The performance sag in your example could be a consequence of the virtual method table (not just because of "sealed" class). If you try to remove the "virtual" word you will see the other results.
    It does not negate the fact that type casting and some other operations are faster with sealed classes, but I think the "sealed" is not something that always makes performance better.

    • @zer0K3lvin
      @zer0K3lvin 2 роки тому +5

      Actually was wondering about that and tested it ... if it's not virtual its just the same speed ... so sealed/unsealed has no impact on none virtual methods.

    • @0shii
      @0shii 2 роки тому

      @@zer0K3lvin Thanks for testing that, I was wondering as well!

  • @volodyasenchak1907
    @volodyasenchak1907 2 роки тому +6

    You noticed in this video that inheritance now is considered an antipattern.
    I tried to find some nice examples of how we can replace inheritance with composition, but I couldn't find some nice examples.
    Could you please make a video on how we can refactor code with inheritance to the composition?)

    • @nickchapsas
      @nickchapsas  2 роки тому +12

      I will make a video on the topic. It's not as simple are replacing class extension with interface implementation. It goes deeper than that

  • @dentjoener
    @dentjoener 2 роки тому +1

    I swear, I don't know if it's your channel or .NET people in general, but this obsession over performance all the time...
    The only good reason to seal classes is because you didn't design them to be inherited anyway. To which I agree, sealed should be the default.

  • @shayvt
    @shayvt 2 роки тому +4

    Can you do a video about the inheritance anti-pattern?

  • @cyex4311
    @cyex4311 2 роки тому +5

    New coder here. What I took away was “sealing classes not meant for inheritance = better performance”.

    • @blo0m1985
      @blo0m1985 26 днів тому

      just use records, they are sealed

  • @Andrei-gt7pw
    @Andrei-gt7pw 2 роки тому +10

    There should be a setting which instructs the compiler to make all classes in a project sealed if they are not inherited. Could be usefull when you don't plan to roll out your code as a reusable library, which is most often the case.

    • @thebigstach919
      @thebigstach919 2 роки тому +1

      Wish someone from development team could say something about this idea.

    • @julkiewicz
      @julkiewicz 2 роки тому

      Probably easier to write a simple post-processing tool in something like Mono.Cecil to do that. You have to consider that in C# it is possible to load DLLs dynamically. Something might get extended in a different compilation unit, the existing tools haven't been designed for this case. But it's maybe a 100 lines in Mono.Cecil to make such a change.

    • @TheJochance
      @TheJochance 2 роки тому

      @@julkiewicz Yup. Late binding very likely goes right to the heart of why there is a performance benefit to doing this. Apparently someone else has tested this and says virtual is the kicker, sealed/unsealed otherwise won't matter.

  • @micmacha
    @micmacha 2 роки тому +6

    As a frequent C programmer, one of the things I appreciate about C# is the ability to throw an OOP concept or trope like garbage collection overboard. There's definitely a place for them, but if I'm doing something like DSP it can be a performance factor of over a thousand just to clean up after myself instead (unchecked, unsafe), and work with buffers directly. So, I appreciate the occasional "do we always need this" introspection from the C# team.

  • @tomwimmenhove4652
    @tomwimmenhove4652 2 роки тому +1

    Actualy, 0.0008ns would be 800 femtoseconds. That is many times faster than any CPU could execute any instruction. It must be just completely optimized away.

    • @davidparker5530
      @davidparker5530 2 роки тому +2

      Exactly my thoughts, what is he using to measure the performance? The lowest level measurement he could possible take is using RDTSC which itself takes roughly 30 clock cycles to execute (10ns on a 3.5Ghz processor). Even if the benchmark is smart enough to measure RDTSC overhead, and subtract it out, the lowest precision you can possibly measure is 1 cycle which is 1 / 3.5Ghz = ~300picoseconds which is still far above 800 femptoseconds.
      If we assume that this Sealed ExampleIntMethod is perfectly optimized, i.e. essentially an immediate load of 420 into the A register and a return instruction (we will even optimize out all the stack pushing of BSP and RSP), we are still looking at ~4 clock cycles to execute the function which is still more than a nanosecond. For example, run the following code with -O2 optimizations: pastebin.com/vGrdT9ib

  • @SilasPeters
    @SilasPeters 2 роки тому +6

    I love the little Hello World eastereggs! Such a personal touch

  • @MagnusBertilsson
    @MagnusBertilsson 2 роки тому +27

    This may be great in theory, but in practice when trying to test either legacy systems or library without a good testing strategy. Sealed classes have stopped me from writing unit test many times. Especially when you want to implement tests without changing legacy code.
    For new systems it might be more applicable, but they will be legacy system one day. So how do you want to leave the code for future developers.

    • @gnack420
      @gnack420 2 роки тому +10

      This is a design flaw in your code. Third party services/libraries should be abstracted using an adaptor that conforms to an interface that you've written. You can then trivially mock the adaptors in your unit tests. There's no need for those third party libraries to be unsealed if you are properly abstracting your dependencies. You should also avoid injecting concrete types as dependencies whenever you can.

    • @MagnusBertilsson
      @MagnusBertilsson 2 роки тому +7

      @@gnack420 Well that is also a question about theory and practice. Yes I know all about abstracting dependencies. I have 10 years experience with looking at old code that either only is the layers of abstractions or looking at code that has no abstractions. And the one thing that made me utter profanities more then others is sealed classes. When trying to test.
      And it’s a lot easier to end to end test code without infrastructure when third party libraries do not use sealed on their classes. Yes I can write a lot of unit tests with my abstractions but if I send the wrong property in the wrong argument in my implementation. The only thing the fast code will produce is more problems for me to clean up in production if QA don’t catch it.

    • @Marfig
      @Marfig 2 роки тому +5

      This is correct Magnus. Unit testing is one of the shortcomings of sealed classes. And being told I have to extend my object model to support unit testing because I sealed all my classes, flies in the face of everything we learned about object data models, and the quest for simplicity and extensibility. I admit there may be outlier use cases in which sealing all my leaf classes is a necessity or a sound design choice. But for the vast majority of object models in the world, even considering C# little semantics flaws and idiosyncracies, sealing a class should be a structural decision about the object model. Not the result of an arbitrary generalization to gain infinitesimal performance gains on an application that has no performance issues in the first place, or where those performance issues are understood to live somewhere else in the code. This wasn't one of Nick's best days.

    • @Marfig
      @Marfig 2 роки тому +3

      Three examples in which I would want to seal my class:
      (1) I'm writing a class with value-type semantics.
      (2) I'm writing a code generator for an engine or interpreter which relies on specific types being consumed.
      (3) I'm writing a utility math class composed entirely of truisms. (On this special case, extending behavior is best achieved through composition).
      All in all, Microsoft advice in the sealed keyword documentation page still stands. In short, do it only if it makes sense. Avoid it otherwise.

    • @FudgeYeahLinusLAN
      @FudgeYeahLinusLAN 2 роки тому

      @@MagnusBertilsson I don't understand. When unit testing a class, you're supposed to test the methods of that class, no? Ergo, instantiate an object of the class, call its various methods with various parameter values, analyze the results. Sealed or no sealed class makes no difference, legacy or brand new class makes no difference.

  • @TheDjblane
    @TheDjblane 2 роки тому +1

    @Nick Chapsas what about public class XXXController : ControllerBase in web api?

  • @ashlar64
    @ashlar64 2 роки тому +7

    Interesting....One case you need to be careful is if you have created a nuget package / dll and you seal a class that would be very useful for your user to inherit from. This has happened to me and it caused me alot of pain.

    • @ArrovsSpele
      @ArrovsSpele Рік тому +3

      Absolutely agree. I cant imagine how i could survive till now, if i hadnt possibility to extend/inherit all kinds of 3rd party libraries.

  • @m5s10
    @m5s10 2 роки тому +7

    Hey Nick, thanks for the great video. I have two questions. 1. Is the performance difference only in .net 7, or is it in older veresions as well (.net 6, 5, .net core, .net framework)? 2. Usually there's no such thing as free lunch. In the video you displayed making class sealed (if possible) as an absolute positive, with no negatives. Are there some known drawbacks to doing it? Thanks :)

    • @nickchapsas
      @nickchapsas  2 роки тому +9

      1, Yes i applied to previous versions as well. 2. The "negative" is that you can't inherit from it anymore but if you were never planning to do so then it's just positive.

    • @m5s10
      @m5s10 2 роки тому +1

      ​@@nickchapsas Thanks for the quick reply. Most of the classes are not inherited anyway, so this might give us some performance gains. I'll give it a shot.

    • @alexander4468
      @alexander4468 2 роки тому

      @@nickchapsas Could you please share your opinion about how to test such sealed classes? could it be measured as "negative" point of this approach? Because I can see a problem with some legacy or some projects with non-structured test strategy where such "sealed by default" might lead to issues when we try to mock them or create a stub for such classes (if there was no adaptors which would allow to mock them instead of the classes directly). Thanks!

    • @yunsha9986
      @yunsha9986 2 роки тому

      @@nickchapsas I second this Nick, could you show a fiddle of how you unit test those sealed classes?

  • @AbhinavKulshreshtha
    @AbhinavKulshreshtha 2 роки тому +8

    As a kotlin dev, I really like the sealed nature of language, But coming from Java/C# background, I used to have a mindset that classes should allow for inheritance. I used to think that just encapsulation means a lot of objects running around in memory. It took me a while, a good mentor, and a lot of performance benchmarks to realize the runtime benefits far exceeds the memory overhead, and also that a badly designed inheritance will actually consume more memory than encapsulating multiple objects.
    Great video as always. I really love all the benchmarks numbers that you show to validate your tips.

    • @fr3ddyfr3sh
      @fr3ddyfr3sh 2 роки тому +8

      Badly designed inheritance has a ton of disadvantages, strong coupling, hard to understand, hard to maintain.
      Sometimes impossible to refactor, because 20 different inherited classes are strongly coupled, and minor changes, can lead to subtle (but devastating) behaviour changes.
      In 90% of the cases:
      Prefer composition over inheritance

    • @ExpensivePizza
      @ExpensivePizza 2 роки тому +4

      @@fr3ddyfr3sh Absolutely agree that you should prefer composition over inheritance in 90% of cases. The only problem with this mantra is that most people don't understand the other 10% of cases.

  • @engineeranonymous
    @engineeranonymous 2 роки тому +1

    While C# copies Java's classes are not "final" by default idea, all methods are non virtual by default in C# unlike Java. While adding a simple "unsealed" keyword might be seemed a little change, it will cause angry email's, long code reviews. So unsealed by default let OOP techniques to be used without a drama. The same can be said for static. Why not make every method, variable static. Less garbage collection, less memory, faster code ? Stack Overflow is using it ????

  • @levmatta
    @levmatta 2 роки тому +2

    Before watching: I Absolutely hate SEALED, cannot estimate how many hours waisted copying disassembled classes and still failing to customize what I needed.

  • @one.pouria786
    @one.pouria786 2 роки тому +6

    I think if ide(s) like Rider and Visual Studio add this feature (Adding sealed keyword in snippet code of Creates a class declaration)
    It will be reasonable and more practical.

    • @EmptyGlass99
      @EmptyGlass99 2 роки тому +1

      Do you know if there is a setting in VS? When I create a new class, it defaults to internal.

    • @nickchapsas
      @nickchapsas  2 роки тому +9

      With the new analyzer you can make rider remind you and I'm pretty sure they will be adding a refactoring too

  • @SvdSinner
    @SvdSinner 2 роки тому +2

    If anyone else might consume your code, PLEASE DON'T seal public classes by default! Sealing public classes that get consumed by other devs basically says "F#@$ Y0U, I DON'T CARE ABOUT WHAT YOU WANT TO DO" I have had multiple times where I've had to waste time writing a bunch of wrapper code for a sealed class because the author of the class thought that it should be sealed since they never considered my use case.
    API writers don't need to support other developers' code that inherits from their class. But they need to let other developers do their jobs without artificially limiting what they can do. Developers know that if they write code that breaks things, then it is their own fault. Don't try to "save" future developers from possibly causing a bug.
    That said, if you NEED the performance, or if you know that your only consumers are people in your same organization that you can unseal the class when asked, go right ahead and seal everything. Seal internal objects. But, DON'T STRIP FUTURE DEVELOPERS OF THE TOOLS TO DO THEIR JOBS. Inheritance is a programming tool, and disabling it by default is BAD.

    • @nickchapsas
      @nickchapsas  2 роки тому +1

      You are thinking about this the wrong way round and you've fallen in that trap because of C# default logic. The actual logic you should have in mind is "Oh this isn't sealed so I can extend it" and "Oh this is seal so there is a reason why I shouldn't extend it"

    • @SvdSinner
      @SvdSinner 2 роки тому +3

      @@nickchapsas No, I think about it in terms of "How can I most efficiently code this for my employer" If I can do something faster and easier-to-maintain by inheriting from a class, I do it. If I'm thwarted by someone who thought they should seal public classes willy nilly, I am being forced to waste time and effort with things like wrapper classes. (BTW, I do love your vids. I just hate the programming trend of forcing other developer to ONLY use your code the way you expect them to.)

    • @nickchapsas
      @nickchapsas  2 роки тому +1

      @@SvdSinner Different schools of thought then. Efficiency is subjective. If your point had any merit then no Android apps would ever be made and modern languages would choose to follow this default behavior.

    • @SvdSinner
      @SvdSinner 2 роки тому +1

      @@nickchapsas Programming trends come and go. Passionate programmers don't always agree on everything.

    • @FudgeYeahLinusLAN
      @FudgeYeahLinusLAN 2 роки тому

      The reason why that other developer didn't think about your use case is because your use case didn't exist when he wrote the code in question. If at a later point some other use case comes along where the original code needs to be changed, then you should strongly consider refactoring the original code completely rather than extending it. It's the fact that you build upon something that isn't valid anymore that creates legacy code, cyclomatic complexity, and by extension big balls of mud. But I guess I shouldn't complain, as an IT consultant, I get rich off of cleaning up the balls of mud that you create by extending invalid code rather than refactoring it. :)

  • @neociber24
    @neociber24 2 роки тому +5

    I tried that, but notice you can't seal some entities when using dotnet EF because they use a Proxy for the DB

    • @fr3ddyfr3sh
      @fr3ddyfr3sh 2 роки тому

      Definitely, that’s how EF and also NSubstitute work.
      But the latter will most likely be used on interfaces

    • @bartdeboer
      @bartdeboer 2 роки тому +1

      True but those are not the type of calls that you expect in a inner loop as they are io bound , so nanosecond improvements won't matter anyway.

    • @FudgeYeahLinusLAN
      @FudgeYeahLinusLAN 2 роки тому

      Yet another reason to not use EF in my book. I'm an EF survivor and have been EF free since 2010. :)

  • @fixgn
    @fixgn 8 місяців тому +1

    Thank you for this video. I enjoy videos about the performance and features of C#.
    By the way, I wanted to mention that in .NET 8 (I tested it on .NET 8.0.101), there are no significant changes in performance when running methods and changing arrays to spans. However, other cases still show the same performance differences. This means that it’s still important to seal your classes in .NET 8.

  • @MrMatthewLayton
    @MrMatthewLayton 2 роки тому +3

    Totally agree. Having been a Kotlin developer for the past few years, I've learned to appreciate sealed (or final) by default, and now I apply it as a matter of habit to C# projects. Whilst .NET doesn't implement sealed by default for classes, it does for structs, which is why you can't extend them. If you look at the IL for a struct, you'll notice they're marked sealed, and as .NET has no mechanism to 'unseal' a type, you simply can't extend them.
    The other thing that would be nice is if C# had a language-level equivalent of Kotlin's 'sealed' (which is not the same as C#'s sealed), where you can create an abstraction that is only intended to be implemented within the same assembly. You can achieve this however by using internal constructors, so that it's not possible for extension beyond the current assembly.

  • @chj915
    @chj915 Рік тому

    It is easier for a new language to comment on something that's been there for many years in an existing language. This might be true that sealing a class will benefit the code in terms of performance. However, it is not the case when you did not have such long historical development in the past. No one would design a language that will be perfect forever. Otherwise, people won't come up a new language every few years. I don't want to think this is a "design flaw" of C#. If it were a design flaw, it would be caught back then already. Any obvious flaw would be resolved at the beginning. The fact it existed and people did not feel wrong about it for many years indicates it is indeed ok in most cases.
    If thinking about today's programming world, lots of things have been changed comparing to 10 or 20 years ago. More micro apps were built, more services built behind API. People are not really depending on SDK, rather more dependency on common agreement such as interface like JSON - which is loosely bound between 2 sides (client & server). You don't really need to inherit a class in order to consume that service anymore. The rapid development around the web/service technology enables us to jump out of the scope of language itself. When coming to a system design, it is common to write code in language A to call another service written in language B. There is really not much of need to inherit the class anymore. However, when you really need to get hands on a particular language's SDK, most likely you DO WANT TO extend the classes from it, hence the "inheritence" of OOP is assumed by default.
    I am not saying "sealing a class by default" is wrong, but changing the default from "not sealing" to "sealing" isn't obsolutely the right decision either, at least that is my opinion.

  • @alphaanar2651
    @alphaanar2651 2 роки тому +1

    8:26 I can see why you did that ;).

  • @M3lodicDeathmetal
    @M3lodicDeathmetal 8 місяців тому

    5:50 this is nonsense, I'm not sure if you talk about this in other videos. The fastest measureable time in theory is one CPU cycle. For a modern 5GHz machine that would be 0.2ns (you, too, have a 4.9 GHz processor). If the benchmark returns a value smaller than this, there's a measuring problem and indeed, dotnet benchmark also warns you about this right below the table, in red: "This method duration is indistinguishable from the empty method duration" and further more, the median is 0ns, which means, half of the benchmarked values were 0ns. So "1000times faster" is nonsense. To measure super fast code you can not purely rely on the benchmark framework. It's a bit tricky. You might need multiple evaluations in the benchmarking function. The benchmark values always contain a bit of noise. The OpenVoid method takes 1 CPU cycle and the OpenInt method takes 4 CPU cycles. So you cannot be faster than openvoid because you cannot be faster than 1 CPU cycle.

  • @3ncy
    @3ncy 2 роки тому +1

    I see the performance differences, but isn't it better, when other people can inherit from your code and add/customise it to their needs?

    • @nickchapsas
      @nickchapsas  2 роки тому

      Only if you designed your code to be customizable for their needs

  • @jdlessl
    @jdlessl 2 роки тому

    Holup. 0.0008 nanoseconds? 800 _femtoseconds_? I'm pretty sure home computers can't even measure timespans that short. That's a tiny, tiny fraction of even a single clock cycle. I'm much more inclined to think that it's a threshold artifact. That is, most of the operations were below the minimum timespan to measure and reported as effectively zero, which got averaged up to some crazy small value by the occasional 1 ns measurement. Whereas the inheritable class tests had a much greater fraction of tests come out to 1ns, dragging the average higher.
    It's like if you take the average of each these values, but first treating anything below 0.5 as 0
    0.4, 0.3, 0.4, 0.6, 0.4, 0.5, 0.4 => 0.16, which is lower than any of the actual reported values.
    vs bumping up each value by just 0.1, again treating anything below 0.5 as zero first
    0.5, 0.4, 0.5, 0.7, 0.5, 0.6, 0.5 => 0.47, seemingly tripling the average, even though the inputs didn't increase anywhere near that much.
    Yeah, look at the SealedInt median value @6:36: 0ns. You'd only get that if the majority of the values were zero, which cannot accurately reflect the true computing time. Can you do an aggregate measurement of a million of each instantiation, rather than trying to time each and every one separately?

  • @wknight8111
    @wknight8111 Рік тому

    I've been making my classes sealed by default for years now. I don't do it for performance reasons (though every little bit helps!), I do it because I don't like to use inheritance when I don't have to. "Prefer delegation over inheritance", etc. I only wish VS made it easier to change the default class template, so I could make those changes more quickly and easily.

  • @nathanieljennings3311
    @nathanieljennings3311 2 роки тому

    Rider has an inspection severity setting for this outside of .NET 7 under Settings / Inspecting Settings / Inspection Severity / C# / Class can be made sealed (non-inheritable)

  • @proosee
    @proosee Рік тому

    Being someone who was integrating with legacy systems, "sealed" key word on public classes is most hated of them all for me - you just can't predict all the future of your system, so I would advice some humbleness on deciding what is something designed for. I know this is a bit of edge case and you can always use reflection, but still: I don't think we should focus on millisecond performance improvements when everywhere I look I see suboptimal algorithms, ridiculous data structures or architectural concepts that are pointless or harmful. And those I mentioned here are not even there as a trade off for readability or performance - quite the opposite in fact.
    Don't get me wrong, I praise developers of those legacy systems for domain specific device handling and such (that's why we were still using them), but you just can predict everything or you can just make a mistake of mixing few things that should be separate by accident.

  • @themiwi
    @themiwi Рік тому

    Man, how I whish I'd could just set a property in csproj (like for nullable) to change the default. Code reviews would be so much easier.

  • @AntonioNoack
    @AntonioNoack 2 роки тому

    you consider 0.16ns a valid result? 🤔 Is your CPU running at 6.2GHz?

  • @root317
    @root317 2 роки тому +4

    Ok this will be interesting. I have never used sealed before.

    • @root317
      @root317 2 роки тому +2

      Ok this was totally worth it. Learned one more thing today. Thanks for the vid Nick, great job as always :)

  • @ahmedfox5935
    @ahmedfox5935 4 місяці тому

    How come it is the way for a very long time when almost all other known language is like this? Java, C++...

  • @briumphbimbles
    @briumphbimbles Рік тому

    Inheritance isn't an anti pattern. People (i.e. inexperienced programmers) just tend to use inherence incorrectly i.e. behaviour reuse instead of to establish type relationships.
    The reason it's not sealed by default is that that its correct use is more common than the want to protect against it so you would in normal use be spending more time adding "unsealed" to everything than you would be doing the contrary. Despite the performance benefits.
    If you don't believe me just look at the extent of inheritance in the .NET framework itself.

  • @jongeduard
    @jongeduard 2 роки тому

    It all reminds me of a thing that the C# designers did right: methods are non-virtual by default. Java is in fact worse, you need to explicitly make your methods final. I have learned earlier that virtual methods are slow, because they require the runtime to perform checks along the inheritance tree all the time.
    But to be honest, I was not aware of such a thing to be te same on the level of entire classes. But it is a logical thing, all for the same reasons.
    I think of course we can all criticize this, but the idea behind those languages started with inheritance in mind as a general feature. Mindsets where very different in the past.
    The idea of gaining the far best performance like native code was already given up anyway I guess. Flexibility is what counted.

  • @slowjocrow6451
    @slowjocrow6451 Рік тому

    Any good talks/examples on "composition over inheritance"?

  • @nadiiazhuravel7179
    @nadiiazhuravel7179 Рік тому

    Would be better if Microsoft worked on internal performance of sealed vs not sealed classes instead of making developers adding an extra word to each class.

  • @Retic_01
    @Retic_01 2 роки тому

    I agree with the point that they should be sealed by default. Much like declaring public.

  • @ShadoFXPerino
    @ShadoFXPerino 2 роки тому

    If a class can be sealed then its functionality could probably be rewritten as a static method for even better performance.

  • @MohitKesarwaniPhoton
    @MohitKesarwaniPhoton Рік тому

    Can't we have something at project level to make all class sealed like we have for nullable

  • @eduardpopescu9109
    @eduardpopescu9109 2 роки тому +2

    I totally agree with this, and I was thinking maybe change the New Class template that Visual Studio uses to create sealed classes?

  • @alexp-ru
    @alexp-ru Рік тому

    69, 520... just random c# numbers :)

  • @nooftube2541
    @nooftube2541 2 роки тому

    But you have tested virtual methods, what about non virtual methods?

  • @cdrbvgewvplxsghjuytunurqwfgxvc

    Public is just a default in the class template. Easily changed.

  • @naturebc
    @naturebc Рік тому

    Why have oo language if you are sealing your classes by default. Makes no sense

  • @Chainerlt
    @Chainerlt 2 роки тому +6

    I've been using c# as my main horse for over a decade, even wrote transpilers to IL and still learned something new today, thanks!

  • @marsovac
    @marsovac Рік тому

    So if we want performance so heavily we need to inherit and seal the class :)

  • @phantomapprentice6749
    @phantomapprentice6749 2 роки тому

    Why even say sealed? If you want to inherit you say what you want to inherit and if not then seal it?

  • @sanyanders
    @sanyanders 2 роки тому +1

    I think right now it's needed to be included into linters warnings by default like "The class %ClassName% is not inherited anywhere and can be made sealed". Is there any suggestion for this on JetBrains YouTrack?

  • @AlexanderBaranski
    @AlexanderBaranski 2 роки тому

    Default classes prevent Long Term Updates without touching the original Codes

  • @ksdmg9282
    @ksdmg9282 2 роки тому

    Is this the performance impact the same for all .net versions?

  • @darkogele
    @darkogele 2 роки тому

    How about static classes vs internal, sealed, private ?

  • @katjejoek
    @katjejoek 2 роки тому +2

    Hi Nick, thanks! I didn’t expect sealed to make such a difference.
    Any chance of the analyzer being released to older versions than .net core 7?

    • @MoireFly
      @MoireFly Рік тому

      Analyzers depend on sdk version. You can use the new sdk to target older versions just fine. Worst case you could multitarget, e.g. for nullability, but that won't be necessary here.

  • @Starbuck1892
    @Starbuck1892 2 роки тому

    Hi Nick, what do you say about the argument that this behaviour violates the open closed principle?

    • @nickchapsas
      @nickchapsas  2 роки тому +1

      That it doesn’t. I’ve answered this already in the comments

  • @Sunesen
    @Sunesen 2 роки тому

    Doesn't sealing a class violate the Open/Closed principle of SOLID?

    • @nickchapsas
      @nickchapsas  2 роки тому +1

      Nop. "Extension" isn't limited to inheritance. Composition can work just fine. Also, SOLID principles are pretty outdated and shouldn't really be used as the defacto guide for writing code

  • @nunoteixeira2129
    @nunoteixeira2129 Рік тому

    thats very cute but on modern c# applications you use a DI container to initialize your classes. Does this performance boost apply to this situation?

    • @nickchapsas
      @nickchapsas  Рік тому

      Sure it does, even in modern apps that use DI.