No video

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

  Рет қаралды 92,285

Nick Chapsas

Nick Chapsas

Күн бұрын

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

Пікірлер: 379
@MHjort9
@MHjort9 Жыл бұрын
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 Жыл бұрын
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 Жыл бұрын
@@davidparker5530 - we have instance members for a reason. Getting the performance of static without changing the code seems like a good deal.
@davidparker5530
@davidparker5530 Жыл бұрын
@@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 Жыл бұрын
@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 Жыл бұрын
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 Жыл бұрын
I’m so the opposite and wish that could change lol (regarding the first part. love these videos)
@weekendrobot
@weekendrobot Жыл бұрын
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 3 ай бұрын
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 3 ай бұрын
totally agree. this approach will make libraries unrepairable in the future.
@hichaeretaqua
@hichaeretaqua Жыл бұрын
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 Жыл бұрын
Nice
@Cameo221
@Cameo221 Жыл бұрын
This is an awesome idea. I shall also do this too.
@JosifovGjorgi
@JosifovGjorgi Жыл бұрын
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 Жыл бұрын
Everything you said can be done with interfaces and composition in C# :)
@JosifovGjorgi
@JosifovGjorgi Жыл бұрын
@@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
@fixgn
@fixgn 7 ай бұрын
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.
@cyex4311
@cyex4311 Жыл бұрын
New coder here. What I took away was “sealing classes not meant for inheritance = better performance”.
@Andrei-gt7pw
@Andrei-gt7pw Жыл бұрын
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 Жыл бұрын
Wish someone from development team could say something about this idea.
@julkiewicz
@julkiewicz Жыл бұрын
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 Жыл бұрын
@@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.
@briansandberg8229
@briansandberg8229 Жыл бұрын
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 Жыл бұрын
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 4 ай бұрын
​@@ZintomV1 You can't evaluate that at compile time because you don't know if an external assembly is inheriting from that class.
@madcroc111
@madcroc111 Жыл бұрын
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 Жыл бұрын
Exactly....it's happened to me a few times.
@MoireFly
@MoireFly Жыл бұрын
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.
@AbhinavKulshreshtha
@AbhinavKulshreshtha Жыл бұрын
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 Жыл бұрын
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 Жыл бұрын
@@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.
@micmacha
@micmacha Жыл бұрын
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.
@Chainerlt
@Chainerlt Жыл бұрын
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!
@silentdebugger
@silentdebugger Жыл бұрын
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 Жыл бұрын
Wouldn't the compiler optimization already know which classes aren't ever inherited in the project, thus quasi-seal them for the build?
@SilasPeters
@SilasPeters Жыл бұрын
I love the little Hello World eastereggs! Such a personal touch
@MrMatthewLayton
@MrMatthewLayton Жыл бұрын
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.
@Krilllind
@Krilllind Жыл бұрын
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!
@thomasschroter3802
@thomasschroter3802 Жыл бұрын
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.
@Galakyllz
@Galakyllz Жыл бұрын
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 Жыл бұрын
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 Жыл бұрын
I limit what other developers can do with my code because other developers aren't as good as me. :)
@Andruuid
@Andruuid Жыл бұрын
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 Жыл бұрын
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 Жыл бұрын
@@nickchapsas Ok Thanks!, I actually think the same
@paulkoopmans4620
@paulkoopmans4620 Жыл бұрын
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 Жыл бұрын
@@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 Жыл бұрын
@@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.
@Gioandgoose
@Gioandgoose 8 ай бұрын
I like the numeric values you use as examples.
@debtpeon
@debtpeon Жыл бұрын
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 Жыл бұрын
Hmm, inheritable by default, but methods not virtual by default.
@matthewwood4756
@matthewwood4756 Жыл бұрын
@@rauberhotzenplotz7722 - “encapsulation” is still one the 3 benefits of OO though….that’s one of the points of inheriting non-virtual methods.
@timseguine2
@timseguine2 Жыл бұрын
@@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 Жыл бұрын
@@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 Жыл бұрын
​@@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.
@ashlar64
@ashlar64 Жыл бұрын
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 Жыл бұрын
Absolutely agree. I cant imagine how i could survive till now, if i hadnt possibility to extend/inherit all kinds of 3rd party libraries.
@one.pouria786
@one.pouria786 Жыл бұрын
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 Жыл бұрын
Do you know if there is a setting in VS? When I create a new class, it defaults to internal.
@nickchapsas
@nickchapsas Жыл бұрын
With the new analyzer you can make rider remind you and I'm pretty sure they will be adding a refactoring too
@klightspeed
@klightspeed Жыл бұрын
The performance improvement on the methods suggests that they are being inlined, and the performance improvements on the is / as would be because it can directly check the type instead of checking if the type being tested is assignable from the type of the value.
@volodyasenchak1907
@volodyasenchak1907 Жыл бұрын
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 Жыл бұрын
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
@obiwanjacobi
@obiwanjacobi Жыл бұрын
Change your class template in your IDE to include sealed by default (and make them internal while you're at it).
@wesplybon9510
@wesplybon9510 Жыл бұрын
Just keep an eye out when you do updates. I've made template changes in VS before and updates will wipe them out.
@ristopaasivirta9770
@ristopaasivirta9770 Жыл бұрын
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 Жыл бұрын
I even wonder, if this is the case for Mono in the first place.
@piotrzdanowski5873
@piotrzdanowski5873 Жыл бұрын
tactical dot in case someone will be less lazy than me and tests it: .
@Xankill3r
@Xankill3r Жыл бұрын
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 Жыл бұрын
@@Xankill3r Thank you for pointing out! Makes sense.
@ristopaasivirta9770
@ristopaasivirta9770 Жыл бұрын
@@Xankill3r Thanks!
@kuljok
@kuljok Жыл бұрын
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 Жыл бұрын
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 Жыл бұрын
@@zer0K3lvin Thanks for testing that, I was wondering as well!
@eduardpopescu9109
@eduardpopescu9109 Жыл бұрын
I totally agree with this, and I was thinking maybe change the New Class template that Visual Studio uses to create sealed classes?
@shayvt
@shayvt Жыл бұрын
Can you do a video about the inheritance anti-pattern?
@timseguine2
@timseguine2 Жыл бұрын
I usually always avoid implementation inheritance. So I have been doing this for a while. And even the general rule is: either design for implementation inheritance or forbid it. I usually design for interface inheritance, so yes, of course I seal my classes since I am not designing them for implementation inheritance.
@MagnusBertilsson
@MagnusBertilsson Жыл бұрын
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 Жыл бұрын
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 Жыл бұрын
@@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 Жыл бұрын
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 Жыл бұрын
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 Жыл бұрын
@@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.
@m5s10
@m5s10 Жыл бұрын
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 Жыл бұрын
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 Жыл бұрын
​@@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 Жыл бұрын
@@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 Жыл бұрын
@@nickchapsas I second this Nick, could you show a fiddle of how you unit test those sealed classes?
@jimread2354
@jimread2354 Жыл бұрын
Wow! I had no idea the performance difference that existed between. I'm really glad I watched this!
@AlFasGD
@AlFasGD Жыл бұрын
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 Жыл бұрын
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 Жыл бұрын
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 Жыл бұрын
@@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 Жыл бұрын
@@gnack420 I agree but I also believe that it's generally good to perform a general fact check
@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.
@vdrasutis
@vdrasutis Жыл бұрын
Nice and short as always, great video
@matthewdee6023
@matthewdee6023 Жыл бұрын
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 Жыл бұрын
Interesting! Where could I find more info on the why?
@matthewdee6023
@matthewdee6023 Жыл бұрын
@@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.
@alxmajor166
@alxmajor166 Жыл бұрын
I agree. The largest accurately measured specimen of the elephant seal was a bull which weighed at least 4 tonnes.
@mindstyler
@mindstyler Жыл бұрын
We really need a way to specify different c# 'versions' so features can be changed retroactively without having to worry about backwards compatibility. Any new project will use the most up to date recommended version and if an older project is upgraded, they can change individual settings to reenable compatibility modes. I think that would be awesome.
@mindstyler
@mindstyler Жыл бұрын
@@MiningForPies no this is not what i mean here at all. i mean: instead of classes being implicitly open by default, and you have to seal them with the sealed keyword, in the recommended version classes would be sealed by default and there would not be a sealed keyword, but rather an 'open' keyword. the same applies to other features, for example _ in lambda is a discard, even in single argument lambdas (which is not currently the case because of backwards compatibility concerns by the .net team) and there's a whole list more of similar features.
@mindstyler
@mindstyler Жыл бұрын
there are already programming languages that have a 'version' model like this. nick has even mentioned it in a video about it a few months back. (though i cannot quite remember which one)
@gnack420
@gnack420 Жыл бұрын
You can specify the language version in your .csproj files.
@mindstyler
@mindstyler Жыл бұрын
@@gnack420 are you people even reading what i am asking for? cause apparently you dont.
@a11d
@a11d Жыл бұрын
Wtf are these replies people don't read 😅 I commented exactly this and saw this comment. Do you know what the stance of the c# team on this is? It should have been discussed at least right?
@jamesmussett
@jamesmussett Жыл бұрын
Ive been making everything sealed for a while now but it is a chore to remember, especially for juniors. I think they should add an unsealed keyword anyway, that way they could have warnings on public types that don’t specify it explicitly.
@peryvindhavelsrud590
@peryvindhavelsrud590 Жыл бұрын
Why not just reuse the existing virtual keyword and a project setting to default to sealed classes?
@1eyewonder27
@1eyewonder27 Жыл бұрын
You could always create a class template or edit the default visual studio class template as an alternative if that is something you think wouldn't harm your team's code
@bluesillybeard
@bluesillybeard Жыл бұрын
I agree, similar to how the public and private keywords work - you don't actually NEED both to write valid code, it's just good practice to specify weather something is public/private rather than leaving it up to a default value.
@queenstownswords
@queenstownswords Жыл бұрын
I suspect if we make sealed a default, a lot of legacy code would break, yes? A code analyzer is the best way forward.
@peryvindhavelsrud590
@peryvindhavelsrud590 Жыл бұрын
@@bluesillybeard It could be done in the same manner as nullable support was added to the project files. Legacy code could omit the setting and would work as previously to avoid breaking changes.
@robertotumini395
@robertotumini395 Жыл бұрын
Probably your best advice until now. Thanks!
@root317
@root317 Жыл бұрын
Ok this will be interesting. I have never used sealed before.
@root317
@root317 Жыл бұрын
Ok this was totally worth it. Learned one more thing today. Thanks for the vid Nick, great job as always :)
@LuigiTrabacchin
@LuigiTrabacchin Жыл бұрын
I Think that with the new feature of C# "Extension everything" this could be adopted in very fast way
@sigma_z
@sigma_z Жыл бұрын
I've been sealing all my classes since forever. I'm happy this performance gain and lock down of inheritance is becoming more mainstream now. Thank you Nick
@dieter5220
@dieter5220 Жыл бұрын
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).
@nathanieljennings3311
@nathanieljennings3311 Жыл бұрын
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)
@peymannaji
@peymannaji Жыл бұрын
Absolutely love this video. Thanks a lot for this video.
@anm3037
@anm3037 Жыл бұрын
Thank you Nick. You just made me christmas
@alphaanar2651
@alphaanar2651 Жыл бұрын
8:26 I can see why you did that ;).
@jongeduard
@jongeduard Жыл бұрын
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.
@volodymyrdombrovskyi8530
@volodymyrdombrovskyi8530 Жыл бұрын
Apart from performance and clarity reasons, sealing the class which implements IDisposable saves you from not implementing dispose pattern
@davemasters
@davemasters Жыл бұрын
Well you learn something new everyday! Thanks Nick
@elemontzis
@elemontzis Жыл бұрын
.. and in no time , best practice SOLID "enhances" to SLID. All this for attacking prematurely a performance -potential- issue-that-really-needs-this-tiny-perf-gain
@nickchapsas
@nickchapsas Жыл бұрын
This has nothing to do with open-close. If anything, this enhances it by limiting it to composition over inheritance. Inheritance is an antipattern.
@elemontzis
@elemontzis Жыл бұрын
@@nickchapsas sorry but I know the trend is about using interfaces these days to assure openness, but still stating it has nothing to do with it and inheritance is a anti pattern, that is quiet a statement. If the visitor pattern has been here and there revisited, singleton has been kicked out, we still got pretty good patterns which are articulated around polymorphism. Cz expressiveness is often more desirable than performance I heard often performance tricks need to be sensibly apply to a fraction of the code base.
@paulkoopmans4620
@paulkoopmans4620 Жыл бұрын
​@@elemontzis At the core of pretty much all of the design patterns though is interfaces, not necessarily inheritance. Like everything in life you can't live with hard lined rules, sometimes you would have to be flexible. If you are implementing a pattern in your own code and you are using visitor or maybe command, of course you can still create a command or visitor base class and create some commands that inherit from your base. Inheritance does have its place and nobody is saying that inheritance should go away. But as you learned that is going to come at a performance price, and it is up to you to accept that. But that does not take away that many of the classes that someone creates are always created with the intent to not be inherited. And be honest, you probably have more of those as well, is my guess.
@elemontzis
@elemontzis Жыл бұрын
@@paulkoopmans4620 I couldn't agree more on the necessity to bind time to time our certainties or the need to revisit what we thought was our working assumptions. I could even agree that for experienced functional developers, inheritance might look odd and cumbersome. And what about enterprise built solutions where inheritance depth is 5+ (few too much to learn and understand the structure of The Thing in a reasonable time). Or misused in place of composition. And yes.. c sharp providing features like interface with default implementation.. opens other doors.. maybe many go4 patterns could be written without having final code based on virtual functions call. So keeping this as an open and genuine discussion, maybe inheritance usage should be strongly limited. But then what happen to solid? Particularly to the L then, the liskov principle?
@paulkoopmans4620
@paulkoopmans4620 Жыл бұрын
@@elemontzis I agree. It is good to keep on having the discussions. What you pointed out is exactly how I experienced it too. Back in the 2000 everybody would extent code by inheritance all over the place. Arguably if the default would have been 'closed' and the developer would have to 'open' purposefully; would we not have created these 5+ levels of inheritance mess in the first place? If I would have gotten warning messages back in the 2000 telling me the potential pitfalls of opening for extension by that mechanism... I might have thought to do things differently. Now, again, if in you own internal classes inside your library or even public facing ones; if you find a decent place to use inheritance you should definitely use it. Therefore I also think that the L from SOLID, does and should not go away. If you are designing code and you need -or- benefit strongly from inheritance then you should use it but adhere but also adhere to the Liskov principle.
@arekxv
@arekxv Жыл бұрын
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 Жыл бұрын
Libraries is where you MUST do it
@TheOmilis
@TheOmilis Жыл бұрын
@@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.
@saddamhossaindotnet
@saddamhossaindotnet Жыл бұрын
Loved it. Thank for sharing!!!
@neociber24
@neociber24 Жыл бұрын
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 Жыл бұрын
Definitely, that’s how EF and also NSubstitute work. But the latter will most likely be used on interfaces
@bartdeboer
@bartdeboer Жыл бұрын
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 Жыл бұрын
Yet another reason to not use EF in my book. I'm an EF survivor and have been EF free since 2010. :)
@Havie
@Havie Жыл бұрын
Always wondered about this , thanks!
@jamesterwilliger3176
@jamesterwilliger3176 Жыл бұрын
I couldn't agree more with this video. I check for this in code reviews and insist that things be sealed unless explicitly needed otherwise.
@engineeranonymous
@engineeranonymous Жыл бұрын
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 ????
@TheAproeX
@TheAproeX Жыл бұрын
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 Жыл бұрын
They apply to .NET Core 3.1 too
@protox4
@protox4 Жыл бұрын
Even older than that, full framework can take advantage of converting virtual calls on a sealed class to direct calls.
@yuriihonchar9336
@yuriihonchar9336 Жыл бұрын
​@@protox4 not really. The results on Full framework(.NET 4.8) show almost no difference between sealed and open classes
@levmatta
@levmatta Жыл бұрын
Before watching: I Absolutely hate SEALED, cannot estimate how many hours waisted copying disassembled classes and still failing to customize what I needed.
@adiazwise
@adiazwise Жыл бұрын
Excellent article Nick thanks , I wonder if this apply for records too.
@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.
@petewarner1077
@petewarner1077 Жыл бұрын
Great video Nick. I enjoyed seeing the performance gain metrics which were a far greater magnitude than I'd thought they would be. I've been sealing classes as a default behaviour for years and it never causes me a problem. I see some comments here about how it affects testing such classes in legacy scenarios - if you are designing the sealed classes you write today correctly, they won't cause you a problem "tomorrow" when they are considered legacy. Sure, you can't control and may swear about legacy classes that are marked as sealed, cause side effects, and have no obvious extension points, but that's not a reason to not use the sealed keyword on our own classes that we can design to be "open to extension, closed to modification" (and if we're claiming we observe the SOLID principles, then the sealed keyword is non-negotiable for the O principle.) As well as ensure that dependencies are still swappable on sealed classes (settable properties, or via the ctor), delegate methods are your friend here, allowing you to swap out expensive behaviours in a test context.
@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.
@mihaimyh
@mihaimyh Жыл бұрын
Where do you got .NET7-RC2, on the download page I see the latest preview7 as the latest available for download?
@phizc
@phizc Жыл бұрын
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 Жыл бұрын
+1: Where do people get RC1/2 from?
@kabal911
@kabal911 Жыл бұрын
Came to ask the same thing
@Barsikr
@Barsikr Жыл бұрын
Those example int method numbers: Ah, I see you're a man of culture as well :D
@rodionsabbath9722
@rodionsabbath9722 Жыл бұрын
thanks Nick, great information.
@joevm3
@joevm3 Жыл бұрын
Thank you for your videos. This is very useful for me.
@3ncy
@3ncy Жыл бұрын
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 Жыл бұрын
Only if you designed your code to be customizable for their needs
@katjejoek
@katjejoek Жыл бұрын
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.
@RC-1290
@RC-1290 Жыл бұрын
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 Жыл бұрын
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?
@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.
@TheDjblane
@TheDjblane Жыл бұрын
@Nick Chapsas what about public class XXXController : ControllerBase in web api?
@TheNorthRemember
@TheNorthRemember Жыл бұрын
good point
@M3lodicDeathmetal
@M3lodicDeathmetal 6 ай бұрын
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.
@tomwimmenhove4652
@tomwimmenhove4652 Жыл бұрын
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 Жыл бұрын
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
@FudgeYeahLinusLAN
@FudgeYeahLinusLAN Жыл бұрын
I avoid inheritance like the plage. I inherited (no pun intended) a project in 2010 where the previous developers made the mistake of relying heavily on inheritance, and it was an absolute pain to work with.
@manmohanmundhraa3087
@manmohanmundhraa3087 Жыл бұрын
Eye opening video. Is same is true for sealed method ?
@sanyanders
@sanyanders Жыл бұрын
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?
@joseluiseiguren7827
@joseluiseiguren7827 Жыл бұрын
Awesome man!!!
@mdonatas
@mdonatas Жыл бұрын
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 :)
@Retic_01
@Retic_01 Жыл бұрын
I agree with the point that they should be sealed by default. Much like declaring public.
@modernkennnern
@modernkennnern Жыл бұрын
I feel like many things, like Sealed being the default, could be changed, similar to NRT(Nullable Reference Types) - by adding a setting in the .csproj file. true true // This is currently not even a feature, but it hopefully will come soon.. and then potentially add a wrapper tag: 2022 // This would then set all the default values (like NRT to enabled, both of the preceding values to true, and so on..) C# is an aging language and has a lot of flawed design decisions. I feel like, at some point, this needs some way of being addressed. Why do we, in 2022, have to live with poor design decisions made in early 2000s when we don't run _any_ code from that era?
@modernkennnern
@modernkennnern Жыл бұрын
That said, Roslyn Analyzers are a great alternative to fixing the flaws. It keeps the flaws in, but makes it impossible to use them
@paulkoopmans4620
@paulkoopmans4620 Жыл бұрын
you personally might not. But I know for a fact that the companies I have worked in since 2005 all are still alive. There is a fair chance that some of the original code is still there and running.
@modernkennnern
@modernkennnern Жыл бұрын
​@@paulkoopmans4620 They could still easily interoperate - It would still compile to the same lowered code. It is however a definitive problem with the consistency of the code across multiple projects, but I'd argue that's also an issue with NRT
@paulkoopmans4620
@paulkoopmans4620 Жыл бұрын
@@modernkennnern I was just commenting on your claim that in 2022 there is no code from that era running anymore. :) Again given that the companies that I wrote .net 1.0 code for, in the 2000's are still around, I do want to believe there is still old code bases around. Now this particular 'flaw' of not sealing by default is even prevalent for code created last month. And I agree is a problem and that it is hard to break the cycle. I see what you are trying to say with comparing it to NRT. Yes; they are solved the same way. But also both of these suffer from the same problem. If you have some old library code sitting somewhere in your massive code base and you never get to address it, it still needs to successfully compile today. Therefore the compiler has to generate instructions that give the same behaviour today as it did 20 years ago. Which is why both NRT and this one will just generate warnings but will compile regardless. The reason why such a flag in a project file could not work is because for some new parts you finally want to start with classes that are sealed by default but this dark grey area of your massive project should not generate a sealed class, and unfortunately both of the lines are identical and the compiler could not tell which one to generate as which type. I appreciate that for a net new project and/or solution it could. But the having the warning and your IDE treating it as such is frankly the same experience.
@Skurdt
@Skurdt Жыл бұрын
The performance benefits also seem to apply (not fully though) for an "open" class that uses sealed override methods. (public sealed override ExampleVoidMethod() { })
@nickchapsas
@nickchapsas Жыл бұрын
Only on the method invocation itself. Having the class sealed applies them to everything for instantiation, to type checks to method calls etc
@yossisternlicht21
@yossisternlicht21 Жыл бұрын
Great video, as usual. One point I noticed in your tutorial (and Stevens issue) is that both the sealed class and the open class are themselves inheriting from a base class. Would the same hold true if both of these classes were not explicitly inheriting another class?
@nickchapsas
@nickchapsas Жыл бұрын
It would yes
@luca-dallavalle
@luca-dallavalle Жыл бұрын
Great video.
@jctrevis
@jctrevis Жыл бұрын
AWESOME content! Do this rule of sealed classes also work for the old .NET Framework? Is there a gain in performance there as well?
@nickchapsas
@nickchapsas Жыл бұрын
Yes the performance benefits have been there since forever
@devon4541
@devon4541 Жыл бұрын
Seems like the performance gain could be a compiler optimization without having to seal classes manually. If there are no extensions of the class, the compiler should be able to know that.
@zabustifu
@zabustifu Жыл бұрын
Not when the classes are public. Anyway, I expect some edge cases could become problematic with such optimizations, so it sounds better to expect programmers to make that explicit in their code.
@davidparker5530
@davidparker5530 Жыл бұрын
How? Your module can be loaded dynamically at runtime and linked with other code that calls it?
@zabustifu
@zabustifu Жыл бұрын
​@@davidparker5530 I didn't test it, but I'm thinking of reflection, for example, but I'm sure there must be other cases too. I can't post links without angering KZfaq, but there's a "How to dynamically create a class?" thread on Stack Overflow that has code samples.
@clashclan4739
@clashclan4739 Жыл бұрын
Hi nick, pls consider design patterns also in upcoming videos. Mainly DDD and eventsourcing. And whats ur opinion on aggregate roots
@EmptyGlass99
@EmptyGlass99 Жыл бұрын
This is a C#/.NET channel - there are already plenty of good videos on design patterns.
@neociber24
@neociber24 Жыл бұрын
I think he did videos about that using MediatR
@thecodeman_
@thecodeman_ Жыл бұрын
You have great videos on that topic - on Milan's channel kzfaq.info
@clashclan4739
@clashclan4739 Жыл бұрын
@@thecodeman_ thank you 😊
@andriisnihyr6497
@andriisnihyr6497 Жыл бұрын
Great video, thank you! I expect there would be a lot of comments from people who oppose sealing everything :D
@slowjocrow6451
@slowjocrow6451 11 ай бұрын
Any good talks/examples on "composition over inheritance"?
@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.
@dentjoener
@dentjoener Жыл бұрын
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.
@SvdSinner
@SvdSinner Жыл бұрын
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 Жыл бұрын
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 Жыл бұрын
@@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 Жыл бұрын
@@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 Жыл бұрын
@@nickchapsas Programming trends come and go. Passionate programmers don't always agree on everything.
@FudgeYeahLinusLAN
@FudgeYeahLinusLAN Жыл бұрын
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. :)
@jdlessl
@jdlessl Жыл бұрын
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?
@darkogele
@darkogele Жыл бұрын
How about static classes vs internal, sealed, private ?
@chrismitchell9936
@chrismitchell9936 Жыл бұрын
Hey Nick, I love this video and agree in 'general', but I see one glaring side affect: Mocking...when a class is sealed, I can't mock it. I can extract an interface, inherit, and then so long as I'm careful to ALWAYS use interfaces, all is well again (and in general, I use a lot of dependency injection and use interfaces, etc.) I worry though that the framework may not allow that...and being able to mock things is quite important...thoughts?
@nickchapsas
@nickchapsas Жыл бұрын
You’re not mocking classes you are mocking interfaces and abstract classes which can’t be sealed
@nadiiazhuravel7179
@nadiiazhuravel7179 11 ай бұрын
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.
What is Span in C# and why you should be using it
15:15
Nick Chapsas
Рет қаралды 252 М.
The New Option and Result Types of C#
15:05
Nick Chapsas
Рет қаралды 58 М.
Harley Quinn's plan for revenge!!!#Harley Quinn #joker
00:49
Harley Quinn with the Joker
Рет қаралды 33 МЛН
If Barbie came to life! 💝
00:37
Meow-some! Reacts
Рет қаралды 68 МЛН
ОБЯЗАТЕЛЬНО СОВЕРШАЙТЕ ДОБРО!❤❤❤
00:45
Harley Quinn's revenge plan!!!#Harley Quinn #joker
00:59
Harley Quinn with the Joker
Рет қаралды 24 МЛН
Why Favor Object Composition Over Class Inheritance? A Deep Dive
19:00
Stop using async void in C#! Do this instead.
13:12
Nick Chapsas
Рет қаралды 57 М.
The weirdest way to loop in C# is also the fastest
12:55
Nick Chapsas
Рет қаралды 250 М.
The Ultimate Guide to C# Records
12:55
Zoran Horvat
Рет қаралды 18 М.
Don't throw exceptions in C#. Do this instead
18:13
Nick Chapsas
Рет қаралды 256 М.
8 await async mistakes that you SHOULD avoid in .NET
21:13
Nick Chapsas
Рет қаралды 311 М.
I forced EVERYONE to use Linux
22:59
NetworkChuck
Рет қаралды 415 М.
Writing C# without allocating ANY memory
19:36
Nick Chapsas
Рет қаралды 147 М.
Don't Use Polly in .NET Directly. Use this instead!
14:58
Nick Chapsas
Рет қаралды 57 М.
Harley Quinn's plan for revenge!!!#Harley Quinn #joker
00:49
Harley Quinn with the Joker
Рет қаралды 33 МЛН