Enjoy Strongly Typed Code Again With Covariant Return Types

Поділитися
Вставка
  • Опубліковано 7 чер 2024
  • Which part of object-oriented design is the hardest to get right?
    A viable candidate for this infamous title is that delicate dance between abstract and concrete types we must go through in every single model we make.
    C# has recently been enriched with an important feature that will help us balance abstract and concrete types: the covariant return types. But what is that feature?
    In this video, you will learn how method overrides and interface implementations can return a more derived type than their base type specifies. This feature, almost trivial in its form, has a tremendous impact on the overall design. Once impossible, at least without a risky downcast, operating at the level of concrete classes where required and at the level of abstract types where allowed has become a reality.
    Become a sponsor to access source code ► / zoranhorvat
    Join Discord server with topics on C# ► codinghelmet.com/go/discord
    Enroll course Beginning Object-Oriented Programming with C# ► codinghelmet.com/go/beginning...
    Subscribe ► / @zoran-horvat
    ▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
    ⚡️RIGHT NOTICE:
    The Copyright Laws of the United States recognize a “fair use” of copyrighted content. Section 107 of the U.S. Copyright Act states: “Notwithstanding the provisions of sections 106 and 106A, the fair use of a copyrighted work, including such use by reproduction in copies or phono records or by any other means specified by that section, for purposes such as criticism, comment, news reporting, teaching (including multiple copies for classroom use), scholarship, or research, is not an infringement of copyright." This video and our youtube channel, in general, may contain certain copyrighted works that were not specifically authorized to be used by the copyright holder(s), but which we believe in good faith are protected by federal law and the Fair use doctrine for one or more of the reasons noted above.
    #csharp #dotnet #objectorientedprogramming
  • Наука та технологія

КОМЕНТАРІ • 24

  • @peep39
    @peep39 Місяць тому +1

    I used this pattern (without knowing about it specifically) in a big .NET 8 WPF project. I work in a tiny software shop and we have a lot of work to do. So, to set up a paradigm for my coworker, I built the UI framework and its engine. We decided on a tabbed interface, and I used host builder to treat each tab type implementation as its own DI scope. The WPF view models for each tab type all inherit from base classes (I needed this to enable the underpinnings). The main view model for each tab - which contains several other view models for other aspects of UI - is abstract and generic, and it has properties to store those other view models. Covariance allows me to treat the concrete tab instances in the framework as consistent types. However, the implementation of each tab uses whatever view models are necessary, and they just get plugged into the generic parameters. As long as they derive from the base view models the framework provides, both consumers are happy. The framework sees the basic type, and each tab has full access to its additional state and operators, without annoying casting or coercion. That was a fun thing to build.

  • @cbgrasshopper
    @cbgrasshopper 2 місяці тому +10

    Would love to see a follow-up that contrasts this with generics.

    • @abj136
      @abj136 2 місяці тому +1

      I learned to use generics to achieve this goal in old C# versions. The mechanism is to make declare class Producer, and then ProductType Product {get;} , and so on, and finally class DerivedProducer : Producer

    • @lextr3110
      @lextr3110 2 місяці тому

      it's actually quite useful with generics too..

  • @billy65bob
    @billy65bob 2 місяці тому +1

    3:00 Oh... That explains why I've never had any luck with it and instead had to resort to passing Generics into the interface to get the return type I want.
    That's the one place I'd want it to work more than any other.

    • @zoran-horvat
      @zoran-horvat  2 місяці тому +2

      I always felt there was something wrong with abstract factories because of this. Worse yet, any abstraction that returns objects, and mostly every one does, is an abstract factory, only not called that.
      So, through most of my career, downcasting was the only way to get to specific operations I might require for various nonfunctional reasons, mostly performance. And I don't like downcasting, it feels like the model is not descriptive enough for what it does.

  • @knixa
    @knixa 2 місяці тому

    will you have a video of the in and out generic keywords in the future? or do you already have one and I've missed it?

    • @zoran-horvat
      @zoran-horvat  2 місяці тому +1

      I have this old video about that: ua-cam.com/video/Wp5iYQqHspg/v-deo.html

  • @piotrkowalski3460
    @piotrkowalski3460 2 місяці тому

    (a bit off topic but I'm really curious)
    I noticed that you often use private properties, while most people prefer readonly fields in the similar context. What's your take on private properties vs fields?

    • @zoran-horvat
      @zoran-horvat  2 місяці тому +1

      Same thing in my opinion when not public, whereas public fields are out of question. Readonly fields seem to me more appropriate for dependencies and properties for state components.
      Two important aspects go in favor of properties, however. Getter can safely be public, which is usually the case in functional modeling. They also support calculated values and stored values in a uniform way, so you can mix and match stored and calculated properties easily in the same class, and even change any of them later without affecting their consumers.
      All those reasons add up to my habit to use properties in most classes.
      From the performance point of view, I expect noon-public auto-properties to be as fast as the fields, though I never measured it. The reasoning is that they access the local field, making it easy for the JIT compiler to optimize them away during compilation.

    • @piotrkowalski3460
      @piotrkowalski3460 2 місяці тому

      thank you for detailed answer!@@zoran-horvat

  • @adambickford8720
    @adambickford8720 2 місяці тому +2

    Very interesting. I generally follow C# to see where java will be in 5-10 years, so I'm usually surprised to see it reversed.
    I also didn't realize java can't handle covariant parameters. I guess I've always just used explicit generics but wondering how I arrived at that.

    • @aldineisampaio
      @aldineisampaio 2 місяці тому

      Yep. If I am not mistaken, Java has covariant return types since 2004 (Java 5) and C# 9 was released in 2020.

  • @ryan-heath
    @ryan-heath 2 місяці тому +1

    Is it not c#13 and dotnet 9?

    • @zoran-horvat
      @zoran-horvat  2 місяці тому +1

      Nope, it's C# 9. The feature has been there for quite some time.

    • @ryan-heath
      @ryan-heath 2 місяці тому +1

      Whoa I stand corrected!
      I vaguely remember this from c++ but I’m not too sure. That’s was ages ago 😅

  • @goldmund67
    @goldmund67 2 місяці тому +3

    While the explanation is very clear, the examples are hurting my head. The most concrete consumer 'C' is using a method not defined in the interface nor abstract classes. While polymorphism allows this, it makes me question the effort of defining the interface at all. It promotes shared properties and methods, but it seems to defeat decoupling and IoC. It's these sort of contradictions that make design patterns so frustrating. But that's not a criticism of your explanation of Covariant Return Types themselves, which is helpful and explanatory as always 🙂

    • @zoran-horvat
      @zoran-horvat  2 місяці тому +1

      I have tried to isolate the building blocks, so to force execution of every possible path. The way how you will apply these elements to some design is up to you, and from that point in I can agree with what you said about different designs.

    • @nickbarton3191
      @nickbarton3191 2 місяці тому

      I had the same reaction but I suppose consumer C is doing something unique and is likely to be in the same assembly. In which case, the special method could be marked as internal so as not to allow leakage into the application at large.

    • @zoran-horvat
      @zoran-horvat  2 місяці тому +1

      @@nickbarton3191 That is not the right assumption. The consumer C can depend on the concrete classes, but doesn't have to be in the same assembly.
      Covariant returns essentially address the abstract factory pattern where a certain consumer might need to depend on a concrete factory,whereas a common scenario is to depend on the abstract factory.
      You will notice that the producer/product types in my demo look the same as the abstract factory implementation.

    • @nickbarton3191
      @nickbarton3191 2 місяці тому

      @@zoran-horvat well OK, but I empathise with the original comment that any consumer would depend on a concrete object. How would you test consumer C without DI and mocs? Isn't that the implication?

  • @Sindrijo
    @Sindrijo 2 місяці тому

    Static Virtual abstract interface members and generic type parameters...

  • @Tvde1
    @Tvde1 2 місяці тому

    nice feature but this is just terrible design and I do not recommend anyone to use this

    • @zoran-horvat
      @zoran-horvat  2 місяці тому

      This video is not about design. There was nothing designed in the demo.