Dang. Really good video. As a self-taught coder I have been using inheritance everywhere for years, and I have run into all the classic problems. I'm only now getting my head around different possible patterns and the situations they are useful for. Trying to make composition more of a go-to tool in my toolbox. The is-a-list vs has-a-list example was extremely clarifying, since it helped me realize I have been using composition with collections since the beginning, so it's not such a new concept. Subscribed, and looking forward to watching more of your vids.
I really love your videos! Not many people can explain it clearly and understandably. I like that even now, when I've got a PhD in computer science and don't write code on a regular basis. Greetings from the former Soviet union!
I had written some huge piece of code following inheritance. This video just made me realise how I would rewrite that code today if given a chance to do it. If 2 classes have to implement a method, i.e. be like something, it should do it through interfaces, and if they have to share some logic, they should do it through composition. Also, welcome back!
Nicely explained. Christopher, can you also share the downsides of going with inheritance incorrectly? This would help understand the implications of picking a wrong choice. Alternatively, what does one gain from going with object composition? If you've shared this in any other video, please point me to it. Thank you!
When you start to use OOP tools unnecessarily, the code becomes messy, full of boilerplate, and hard to change. Think of inheritance as "binding more tightly" than composition.
“is a” > class inheritance. “has a” > class composition. “can do”> interface implementation. “can do” with some ‘is a’ abstract class implementation of interface. “Contains one or more of” > class/object aggregation. I use interfaces for just about everything, but create abstract classes that implementation those interfaces with I want shared code reuse as well as polymorphic behavior; however, c# now has default interface implementation via virtual signature definitions, so the lines are getting a bit more blurred, and each solution tends to various architecturally. In any case, ALWAYS favor composition over inheritance.
Incredible video. Got me captivated with the way u explained each point throughout the video, rarely happens when trying to study on yt. Keep it up, looking forward to new content.
Great video man I think inheritance, composition, and interfaces are something that is taught everywhere but rarely do they teach you when and how to use it properly
Great video as always! I really like your way of explaining these concepts. Not just in this video but in all I have seen from you so far. I feel your explanations are concise and to the point, without leaving room for ambiguity, which I really appreciate.
While watching, I thought to ask your perspective/thoughts about POP (Protocol Oriented Programming), but then you made a good lesson about it out of this talk.
I had been subclassing for a whilewithout deep thinking and reason. after studying design pattern, I can compose or confirm interface with makesense. thank you
First of all glad you’re back on the youtube stage 🎉 Second - how/where/when would you instantiate the list class for backpack and warehouse to use. Because backpack and warehouse are composed of things including the list class we should not be triggered/scared etc. that we’re tight coupling them? Would it also make sense to use composition with an interface rather than a concrete object. Not sure the list concept would ever change but the list could be a paper sheet and then turn out into Notes app on a tablet device 😊
@@ChristopherOkhravi, I really like ! But, can you give an example in which it is reasonable to use inheritance ? Because, in the last part of this video, just combined subtypes polymorphism and object composition ! Kindly ! 😊
Yes and yes 😊 The more nuanced answer is ofc that it depends. But if you use that as a general rule of thumb then it is a good rule of thumb 😊😊 Thank you for asking. 🙏
Use inheritance when you have a complicated algorithm of several steps that could be differ in implementations, but the core algorithm remains the same. In such way you can eliminate a duplication of the complicated algorithm implementing in derived classes only necessary steps.
Awesome explanation! But then if I understood correctly, you could achieve more or less the same using inheritance (given that you want both hierarchical reuse and subtyping) and using interface + composition. I also hear that you would favor the second approach, but then is there a specific case where you would choose inheritance (instead of interface + composition)?
I’ve been coding in golang for the past two years and I feel like I’m always running up against the fact that I can’t override things the way you can in normal OOP languages. I’m going to need to recall the cases that bit me but I’ll come back here if I do
Beautiful explanation! The only thing that confuses me is what if I use inheritance to inherit properties from base class? Just properties, no methods - does the same rule apply.
1. Can you provide please the functional programming equivalent to every OOP principle/strategy you demonstrated so far since beginning to upload again on youtube? 2. What are your thoughts on languages like Eiffel that took the care to implement multiple inheritance "properly"?
Hmm. Thank you very much for the feedback 😊🙏 Would you care to elaborate on what was confusing? It seems to me that the terminology should be applicable for many statically typed OO languages since many have similar inheritance mechanisms. Do you have a specific language in mind where this terminology becomes inappropriate? Thank you again for taking the time to watch and discuss 😊🙏
@@ChristopherOkhravi IDK, maybe its just me, but I don't think of inheriting from a class, that has no definitions, as something other than inheritance. When i think of inheritance, it may or may not involve code reuse, but that is incidental. My ultimate goal is to describe a relationship, which happens irrespective of details of the implementation.
At 4:32, to make a case for hierarchical reuse of code, methods in sub classes need not always call the method/s in super class. Template design pattern is a classic example of hierarchical code re-use that uses inheritance effectively. What do you think?
I completely agree. I have 5+ mins of deleted scenes from this video (because I think my execution was too poor) that I will release on my Patreon. In that clip I talked about Template Method Pattern (among other things) so I personally think you are spot on 😊🙏 Template Method for a a valid use case for inheritance. It could certainly still be argued that composition plus subtyping is a better solution but there’s nothing inherently problematic with Tenplate Method imho 😊😊 Thanks for the comment.
It is true, appreciated, Christopher. I think you have experienced in game development, right? please make some videos about component based architecture and different software architectures like onion architecture, etc.
100% agree. Imho there is 0 reason left to use inheritance now that we have default interface methods. Was actually thinking about doing a video on precisely this but haven’t figured out how to make it relevant for non C# programmers. Thanks for commenting! 😊🙏
@@ChristopherOkhravi That's the beauty of this modeling. UML being language agnostic leaves the implementation detail up to the developers. It is their job to interpret the blueprint and build the code the best way the language used to implement allows you to. Years ago, you had to do it the way you show here (with the extra class) in Java because default interface methods were not possible. Today, it's a different thing. Now, we can take "creative license" liberty to deviate a bit from the model and implement it using just interfaces.
One reason I might consider using inheritance is if the constructors are not accessible. For example, you need to extend the Activity class in Android.
Ok let's say we have this situation: I have a bunch of classes that share the exact same 3 methods. I need hierarchical reuse of code. I can either create a base class, and inherit from it, or create another class, then compose it and still duplicate the methods and delegate the calls? Sounds redundant. Or, I could have this new class (with the 3 methods) as a field of each of my initial classes, and when I'd want to access the method, I would access it through this field (violating the law of Demeter)? It sounds kind of confusing. I'd still go with inheritance here.
The ideal use case for inheritance is when you needs lots of subclasses (let's say 1000) that all share most of the same code (let's say 1000 methods shared). Using composition is crazy in this scenario because you have to create passthru functions for all of these methods for no good reason. Using composition instead of inheritance would result in 1 million passthru functions that serve no purpose!!!! And this is even though we don't need polymorphism.
So instead of using Traits as a code reuse for Subtypes (with an interface), you want to inject the implementation of another class instance, essentially the same implementation the Trait would describe, guess it streamlines the dependency overview.
Till now my view was, if you couldn't inherit from a class (because it sealed in C# for example) then use composition. I mean, composition was a workaround solution, not a "primary idea" in "factorisation" of code. But I still think taht if i need a spécial DIctionary, I implement a new class that inherit Dictionary...
Very good advice but I would go a bit further. Even if you need both subtype polymorphism and code reuse, ask yourself "how likely is it that the requirements for this particular feature will change?" Code always changes, requirements always change, nothing stays the same. The more the requirements change, the more the code changes, the higher the likelihood that you will not need BOTH of the features of inheritance, and you'll find yourself having to refactor and break up a large class hierarchy in order to implement the desired behavior. A nasty business. From my experience, business code, the part which changes the most and often in ways hard to predict, is the least suitable for inheritance. In the business world a duck will start speaking, the dog will fly and the spider will walk on only two legs. Whatever hierarchy you try to devise is doomed to failure, changing requirements will eventually demolish it. Non-business code (eq infrastructure code like an authentication module or a JSON parsing one) is less capricious, so it might be a better candidate for inheritance. But even then, exercise caution,
What are your thoughts about this scenario: In Java, interfaces can have default methods with implementation. Recently I refactored a library of classes representing specific types of web elements (for Selenium tests), and all those web elements have a base class with methods that are common to all the web elements and some of the web elements may override the implementation and others may use the default implementation. I saw that some web elements could be disabled and others cannot, so I extracted the IsDisabled() method into a default method of a new interface and had the web elements that can be disabled implement that interface, rather than copy & paste the same function in multiple classes. Would you consider that good or bad?
It's all well and good in theory, yes. But not every language/framework implements features considering the correct patterns which forces you to fallback to what you know to work. For example, in spring data jpa, audit annotations by hibernate, doesn't work inside embeddable which in turn makes it impossible to do an "audit" object composition in a jpa entity and you need to fallback to inheritance to reuse auditing entities, unless you go for custom implementation yourself, which, again, may not be practical (a relatively simple example). Or another: Java, C# doesn't support multiple inheritance because of the diamond problem which should never have been decided by the language (C++ implemented it, no problem).
is object composition basically dependency injection? Instead of inheritance you’d just Inject a class instance into your other class and use its methods
What if we have class Animal and class Cat 🐈 And we are just defining the contract/fields ( no methods) Obviously cats will have some common characteristics with animal So it makes sense to do Class cat : Animal rather than Class cat { Public Animal animal ( get; set;) } I guess I'm comparing oranges and apples now? 😅 @Christopher I think what you have explained makes sense when your class has behaviours as well. ( aka methods)
thanks, very insightful however, in C++ using an interface is actually inheriting it - I mean that the title might be confusing. But of course, the fact of interfaces having or not a base method is something that occurs often and it's a very good criterium
@@ChikitoPOWAin C++, the (java) interfaces are the so-called pure abstract classes, that is, classes with 0 methods implemented (except the default destructor) these pure-abstract classes are then inherited with either a base (shared) class, or directly implemented by several children classes
back to your question, C++ classes (whether they are or not pure-abstract or not) are declared in the header files, and implemented in the .cpp file. I mean, not all header files describe interfaces (pure abstract classes). So it depends on whether the methods are implemented or not. Warning: some people implement some of the C++ methods directly in the header files. This is something I do not like at all and I never do. However, it is of course valid C++.
I would agree 😊 But I can see how some would prefer the inheritance solution in some cases and so as long as it is a sensible use of inheritance o would not argue too much. Better to prioritize moving forward is what I’m thinking 😊 Thank you for commenting 🙏😊
As opposed to? If you went the composition route, then you end up... 1. injecting behaviours into the superclass - these behaviours tend to know quite a lot about the class their being injected into. 2. they also tend to be quite limited and limiting in scope - what happens if you need multiple behaviours in a single compositional inheritance? How do you coordinate these? They get messy, quickly. Inheritance, with virtual/overridable methods give you the flexibility and the readability that compositional inheritance does not - though you do need to think about when to use traditional inheritance this closely.
@@jimiscott It not a theory, this is a well understood topic. Composition gives you better control over your coupling. It can be slightly more effort but ime the gains of inheritance are fragile at best and a disaster at worst.
@@adambickford8720 Whilst I agree that inheritance used wrongly can lead to complications, it should not be thrown out with the baby's bathwater. In our large (1M Lines) middleware/integration platform we have used inheritance to great affect to allow both ourselves and our partners to allow us/them to write add-ins to interface/integrate with different APIs/solutions. An example of this is that we allow our writer classes to be inherited and their methods overridden. These objects take a dynamic model and translate a dataset to a specific format (JSON, CSV, Xml, CSV, etc) - we have writer classes for each type of format. Each addin can (this is not always the case) inherit a writer class to implement it's own custom logic for a specific requirement. For example, an addin may need to encode some data into a specific base64 form when trying to send/upload/post images OR it may need to perform a series of API requests to translate a value/set of values to something specific to solution/service/API being integrated. Inheritance gives us the ability to override the specific method(s) to do this - furthermore we can maintain state much more easily than say if we used composition. Inheritance has given us the ability to rapidly develop these addins, they are succinct, can be easily tested and are maintainable.
Thank you for supplying an alternative perspective. Would you care to elaborate why you think this is controversial? My argument is not that you should do “two things” in a sense that it would violate SRP. The point is: Both hierarchical reuse of code and subtype polymorphism could be used for the same “feature” or “thing”, and inheritance is only a suitable solution if you need both of those to succinctly implement your one feature or thing. Otherwise inheritance is a worse solution than the alternative (which would be either composition or subtype polymorphism through interfaces). Please do feel free elaborate 😊 Thank you again 😊🙏
I wish you went more into the reasoning behind your advice but i do agree with the general sentiment. I've always had a bad time with inheritance and I'm sure most people have, but i used to question if it's because I'm not good at using it or if it's just not a good paradigm. I've been avoiding inheritance like the plague for the last year, it's difficult to debug, it's awful for code readability and i spend more time trying to fit my program into the paradigm rather than writing code to fit my program's requirements. I think the times when OOP is actually a good way to solve a problem are much fewer than people realize even today. I think it's almost always best avoided. Composition is infinitely more flexible and doesn't force you to literally plan out the whole structure of your application before actually writing the application. Humanity went a step back with the misuse and overuse of modern day OOP and i think this calls for a huge moment of self reflection for all of mankind about how we are prone to accepting things as truth because of general consensus.
One exception I can think of right now : sometimes I use inheritance to enforce identicalness across things, for exemple : Imagine a web application where every UI elements are defined with components called "blocks" (dozensss of them), it might make sense to inherit all different blocks from a parent class ("AbstractBlock" for exemple) even if blocks doesn't overwrite methods from the parent class, simply because when the day comes where you need to implement a feature inside ALL blocks, I would rather edit a single file than edit dozens of them ! (and maybe miss some blocks created in an un-merged branch). Or someone might not know that when you create a new block you need to implement X, Y and Z features. It's a lot less prone to human errors when the only thing to remember is "you need to extend from this class and that's it".
"just the fact that we want to reuse code, does not justify the use of inheritance" Nonsense. The sole purpose of inheritance is code reuse (reuse of procedures/methods), similar to how procedures serve the purpose of reusing sequences of operations. However, inheritance operates at a higher level. The connection between inheritance and polymorphism is coincidental. Initially, inheritance was the sole method for implementing polymorphism. Subsequently, polymorphism acquired its own implementation mechanism known as interfaces.
You've not provided much context, so I'll assert my own: In languages like C# and Java, inheritance does more than just facilitate code reuse. The polymorphism manifesting from inheritance is not coincidental but an intended feature of these languages. As such, having a class inherit from another carries semantic meaning: it implies an is-a relationship; it implies substitutability. When you subclass a class, you make an implied promise to follow its contract. If you never cared about the contract and only about the code, it's easy to (knowingly or not) break the contract, which can lead to all sorts of hard to find bugs in other parts of the system. Composition is a more basic functionality that doesn't require inheritance yet still enables code reuse. It doesn't carry any unintended semantic meaning and encapsulates the implementation detail of code sharing (fully or partly, depending on whether you inject the component), making the class more robust (you can shield users of your class from changes to the "shared" implementation, maintaining their contract with your class independent of such changes).
as a senior developer , it is very good explanation.
this is the best explanation I have come across. Makes it easier to remember and easier to convey the message to fellow devs
Dang. Really good video. As a self-taught coder I have been using inheritance everywhere for years, and I have run into all the classic problems. I'm only now getting my head around different possible patterns and the situations they are useful for. Trying to make composition more of a go-to tool in my toolbox. The is-a-list vs has-a-list example was extremely clarifying, since it helped me realize I have been using composition with collections since the beginning, so it's not such a new concept. Subscribed, and looking forward to watching more of your vids.
I really love your videos! Not many people can explain it clearly and understandably. I like that even now, when I've got a PhD in computer science and don't write code on a regular basis. Greetings from the former Soviet union!
Great simple explanation of something I've seen done wrong hundreds of times.
I had written some huge piece of code following inheritance. This video just made me realise how I would rewrite that code today if given a chance to do it. If 2 classes have to implement a method, i.e. be like something, it should do it through interfaces, and if they have to share some logic, they should do it through composition. Also, welcome back!
Exactly this. Thank you for sharing! 😊🙏
first time i've clearly understood when to use interfaces and object composition over inheritance. love your videos
Nicely explained. Christopher, can you also share the downsides of going with inheritance incorrectly? This would help understand the implications of picking a wrong choice. Alternatively, what does one gain from going with object composition? If you've shared this in any other video, please point me to it. Thank you!
I'd watch a vid about that too!
When you start to use OOP tools unnecessarily, the code becomes messy, full of boilerplate, and hard to change. Think of inheritance as "binding more tightly" than composition.
“is a” > class inheritance. “has a” > class composition. “can do”> interface implementation. “can do” with some ‘is a’ abstract class implementation of interface. “Contains one or more of” > class/object aggregation. I use interfaces for just about everything, but create abstract classes that implementation those interfaces with I want shared code reuse as well as polymorphic behavior; however, c# now has default interface implementation via virtual signature definitions, so the lines are getting a bit more blurred, and each solution tends to various architecturally.
In any case, ALWAYS favor composition over inheritance.
I review your videos several times! They are very very useful in my professional path towards Software Architect
Thank you. Happy to hear it’s useful. 😊
Best instructor ever. Chris is the best.
Incredible video. Got me captivated with the way u explained each point throughout the video, rarely happens when trying to study on yt. Keep it up, looking forward to new content.
Great video man I think inheritance, composition, and interfaces are something that is taught everywhere but rarely do they teach you when and how to use it properly
If there was an example (code) of good inheritance, like you did with the interface video, this would be 10/10, IMO.
Great video as always! I really like your way of explaining these concepts. Not just in this video but in all I have seen from you so far. I feel your explanations are concise and to the point, without leaving room for ambiguity, which I really appreciate.
Thank you very much for the feedback. Appreciated. 🙏😊
You are an unreasonably effective teacher! Keep up the great work!
due to your design pattern course i am able to grab all logics eaisly, thank you🙂
Kind of realized this while struggling on some code recently, but wasn't sure. Love how you captured the points well. Subscribed!
While watching, I thought to ask your perspective/thoughts about POP (Protocol Oriented Programming), but then you made a good lesson about it out of this talk.
We love your videos so much please never stop teaching ❤
I couldn't be happier with your videos. Thanks for your time and effort.
I had been subclassing for a whilewithout deep thinking and reason. after studying design pattern, I can compose or confirm interface with makesense.
thank you
First of all glad you’re back on the youtube stage 🎉
Second - how/where/when would you instantiate the list class for backpack and warehouse to use.
Because backpack and warehouse are composed of things including the list class we should not be triggered/scared etc. that we’re tight coupling them?
Would it also make sense to use composition with an interface rather than a concrete object.
Not sure the list concept would ever change but the list could be a paper sheet and then turn out into Notes app on a tablet device 😊
Glad you're back! Composition over inheritance is something you usally learn the hard way :P
😆
@@ChristopherOkhravi, I really like !
But, can you give an example in which it is reasonable to use inheritance ? Because, in the last part of this video, just combined subtypes polymorphism and object composition !
Kindly ! 😊
Damn, this video is SO GOOD!! Your recent videos are one of the best contenet about programming!
Thank you 🙏😊 I’m very happy to hear that the content is useful. Please feel free to share with others who you think might benefit from it. 😊
I sure will!
I still find it difficult to actually use it. But practise makes perfect I think. Thank you for another super explanation.
Should we do object composition by putting an object through the constructor?
Will in this case this be an example of dependency injection?
Yes and yes 😊 The more nuanced answer is ofc that it depends. But if you use that as a general rule of thumb then it is a good rule of thumb 😊😊 Thank you for asking. 🙏
I laughed when you whispered object composition, I just loved it haha.
😊😊
Use inheritance when you have a complicated algorithm of several steps that could be differ in implementations, but the core algorithm remains the same. In such way you can eliminate a duplication of the complicated algorithm implementing in derived classes only necessary steps.
Some languages do not have interfaces, but use subtype polymorphism for that (looking at c++)
Fantastic explanation
Love your videos, as always very informative.
Awesome explanation! But then if I understood correctly, you could achieve more or less the same using inheritance (given that you want both hierarchical reuse and subtyping) and using interface + composition. I also hear that you would favor the second approach, but then is there a specific case where you would choose inheritance (instead of interface + composition)?
Now I finally understand why Golang team provides composition and Interfaces and they refuses to add Inheritance to the language
Same for Rust
I’ve been coding in golang for the past two years and I feel like I’m always running up against the fact that I can’t override things the way you can in normal OOP languages. I’m going to need to recall the cases that bit me but I’ll come back here if I do
Beautiful explanation! The only thing that confuses me is what if I use inheritance to inherit properties from base class? Just properties, no methods - does the same rule apply.
1. Can you provide please the functional programming equivalent to every OOP principle/strategy you demonstrated so far since beginning to upload again on youtube?
2. What are your thoughts on languages like Eiffel that took the care to implement multiple inheritance "properly"?
Thanks, very well explained.
I have to say, this was a bit confusing until i realized you were talking specifically about C#.
Hmm. Thank you very much for the feedback 😊🙏 Would you care to elaborate on what was confusing? It seems to me that the terminology should be applicable for many statically typed OO languages since many have similar inheritance mechanisms. Do you have a specific language in mind where this terminology becomes inappropriate? Thank you again for taking the time to watch and discuss 😊🙏
@@ChristopherOkhravi IDK, maybe its just me, but I don't think of inheriting from a class, that has no definitions, as something other than inheritance.
When i think of inheritance, it may or may not involve code reuse, but that is incidental. My ultimate goal is to describe a relationship, which happens irrespective of details of the implementation.
Wow so clear explanation!! ❤
Love your explanations
At 4:32, to make a case for hierarchical reuse of code, methods in sub classes need not always call the method/s in super class. Template design pattern is a classic example of hierarchical code re-use that uses inheritance effectively. What do you think?
I completely agree. I have 5+ mins of deleted scenes from this video (because I think my execution was too poor) that I will release on my Patreon. In that clip I talked about Template Method Pattern (among other things) so I personally think you are spot on 😊🙏 Template Method for a a valid use case for inheritance. It could certainly still be argued that composition plus subtyping is a better solution but there’s nothing inherently problematic with Tenplate Method imho 😊😊 Thanks for the comment.
It is true, appreciated, Christopher. I think you have experienced in game development, right? please make some videos about component based architecture and different software architectures like onion architecture, etc.
5:37 Now in Java, you can also use Interfaces with default methods to get the best of both worlds. Like the Mandalorian would say: "This is the way!"
100% agree. Imho there is 0 reason left to use inheritance now that we have default interface methods. Was actually thinking about doing a video on precisely this but haven’t figured out how to make it relevant for non C# programmers. Thanks for commenting! 😊🙏
@@ChristopherOkhravi That's the beauty of this modeling. UML being language agnostic leaves the implementation detail up to the developers. It is their job to interpret the blueprint and build the code the best way the language used to implement allows you to. Years ago, you had to do it the way you show here (with the extra class) in Java because default interface methods were not possible. Today, it's a different thing. Now, we can take "creative license" liberty to deviate a bit from the model and implement it using just interfaces.
interface default methods were introduced in java a long time ago, since version 8 if i remember correctly
@@mczn9499 you'll be surprised how many people are still coding with older versions of Java.
One reason I might consider using inheritance is if the constructors are not accessible. For example, you need to extend the Activity class in Android.
nice video... i have a question, is this topic related to liskov substitution in any way
Ok let's say we have this situation: I have a bunch of classes that share the exact same 3 methods. I need hierarchical reuse of code. I can either create a base class, and inherit from it, or create another class, then compose it and still duplicate the methods and delegate the calls? Sounds redundant.
Or, I could have this new class (with the 3 methods) as a field of each of my initial classes, and when I'd want to access the method, I would access it through this field (violating the law of Demeter)? It sounds kind of confusing.
I'd still go with inheritance here.
Perfect video. You're the best
All my support for you man!❤
Another great one. Thanks!
What about in languages like Python which don't have interfaces?
The ideal use case for inheritance is when you needs lots of subclasses (let's say 1000) that all share most of the same code (let's say 1000 methods shared). Using composition is crazy in this scenario because you have to create passthru functions for all of these methods for no good reason. Using composition instead of inheritance would result in 1 million passthru functions that serve no purpose!!!! And this is even though we don't need polymorphism.
As Always, high quality content
thanks for sharing
So instead of using Traits as a code reuse for Subtypes (with an interface), you want to inject the implementation of another class instance, essentially the same implementation the Trait would describe, guess it streamlines the dependency overview.
Anither great explanation ❤
Tack så mycket.
Each to their own
Awesome explanation!
Till now my view was, if you couldn't inherit from a class (because it sealed in C# for example) then use composition.
I mean, composition was a workaround solution, not a "primary idea" in "factorisation" of code.
But I still think taht if i need a spécial DIctionary, I implement a new class that inherit Dictionary...
Very good advice but I would go a bit further.
Even if you need both subtype polymorphism and code reuse, ask yourself "how likely is it that the requirements for this particular feature will change?" Code always changes, requirements always change, nothing stays the same. The more the requirements change, the more the code changes, the higher the likelihood that you will not need BOTH of the features of inheritance, and you'll find yourself having to refactor and break up a large class hierarchy in order to implement the desired behavior. A nasty business.
From my experience, business code, the part which changes the most and often in ways hard to predict, is the least suitable for inheritance. In the business world a duck will start speaking, the dog will fly and the spider will walk on only two legs. Whatever hierarchy you try to devise is doomed to failure, changing requirements will eventually demolish it.
Non-business code (eq infrastructure code like an authentication module or a JSON parsing one) is less capricious, so it might be a better candidate for inheritance. But even then, exercise caution,
What are your thoughts about this scenario: In Java, interfaces can have default methods with implementation. Recently I refactored a library of classes representing specific types of web elements (for Selenium tests), and all those web elements have a base class with methods that are common to all the web elements and some of the web elements may override the implementation and others may use the default implementation. I saw that some web elements could be disabled and others cannot, so I extracted the IsDisabled() method into a default method of a new interface and had the web elements that can be disabled implement that interface, rather than copy & paste the same function in multiple classes.
Would you consider that good or bad?
what about inheritance for data classes?
Thank you!
It's all well and good in theory, yes. But not every language/framework implements features considering the correct patterns which forces you to fallback to what you know to work.
For example, in spring data jpa, audit annotations by hibernate, doesn't work inside embeddable which in turn makes it impossible to do an "audit" object composition in a jpa entity and you need to fallback to inheritance to reuse auditing entities, unless you go for custom implementation yourself, which, again, may not be practical (a relatively simple example).
Or another: Java, C# doesn't support multiple inheritance because of the diamond problem which should never have been decided by the language (C++ implemented it, no problem).
is object composition basically dependency injection? Instead of inheritance you’d just Inject a class instance into your other class and use its methods
@ChristopherOkhravi Not really off topic for those of us who listen to music while programming, who is your favorite Melodic Death Metal Band?
Such a random question 😊😊 In my younger days there was a time when I listened to Soilwork 😊 But I’m not really a metal person 😊😊
Typescript have subtype polymorphism without inheritance, so only composition matter?
Yep and yep! Great video! Love this! #LoveThis
Then, when do we need to do actual inheritance?
cool, I dig my code while watching
What if we have
class Animal
and
class Cat 🐈
And we are just defining the contract/fields ( no methods)
Obviously cats will have some common characteristics with animal
So it makes sense to do
Class cat : Animal
rather than
Class cat
{
Public Animal animal ( get; set;)
}
I guess I'm comparing oranges and apples now? 😅 @Christopher
I think what you have explained makes sense when your class has behaviours as well. ( aka methods)
Thank you sir, amazing! 😊
Can someone please explain what is 'hierarchical reuse of code'? What does it mean? I can't understand the first example at all...
thanks, very insightful
however, in C++ using an interface is actually inheriting it - I mean that the title might be confusing. But of course, the fact of interfaces having or not a base method is something that occurs often and it's a very good criterium
Ah. Good point. 🤔 Sometimes I get too stuck in C# which is what I do most of my thinking in. Thank you! 🙏😊
Wouldn't a header file play the role of interface in C++?
@@ChikitoPOWAin C++, the (java) interfaces are the so-called pure abstract classes, that is, classes with 0 methods implemented (except the default destructor)
these pure-abstract classes are then inherited with either a base (shared) class, or directly implemented by several children classes
@@ChristopherOkhraviooh C#, I see, now I understand why you said so haha 😄
(I write C++ for a living)
back to your question, C++ classes (whether they are or not pure-abstract or not) are declared in the header files, and implemented in the .cpp file. I mean, not all header files describe interfaces (pure abstract classes). So it depends on whether the methods are implemented or not.
Warning: some people implement some of the C++ methods directly in the header files. This is something I do not like at all and I never do. However, it is of course valid C++.
This man!
Great work❤
Smashing explanation! Where is the furry one though 😺?
great
Even if you have the perfect storm of needing both, as soon as that changes, you're still holding the inheritance baggage.
I would agree 😊 But I can see how some would prefer the inheritance solution in some cases and so as long as it is a sensible use of inheritance o would not argue too much. Better to prioritize moving forward is what I’m thinking 😊 Thank you for commenting 🙏😊
As opposed to? If you went the composition route, then you end up...
1. injecting behaviours into the superclass - these behaviours tend to know quite a lot about the class their being injected into.
2. they also tend to be quite limited and limiting in scope - what happens if you need multiple behaviours in a single compositional inheritance? How do you coordinate these? They get messy, quickly.
Inheritance, with virtual/overridable methods give you the flexibility and the readability that compositional inheritance does not - though you do need to think about when to use traditional inheritance this closely.
@@jimiscott It not a theory, this is a well understood topic.
Composition gives you better control over your coupling. It can be slightly more effort but ime the gains of inheritance are fragile at best and a disaster at worst.
@@adambickford8720 Whilst I agree that inheritance used wrongly can lead to complications, it should not be thrown out with the baby's bathwater. In our large (1M Lines) middleware/integration platform we have used inheritance to great affect to allow both ourselves and our partners to allow us/them to write add-ins to interface/integrate with different APIs/solutions.
An example of this is that we allow our writer classes to be inherited and their methods overridden. These objects take a dynamic model and translate a dataset to a specific format (JSON, CSV, Xml, CSV, etc) - we have writer classes for each type of format. Each addin can (this is not always the case) inherit a writer class to implement it's own custom logic for a specific requirement. For example, an addin may need to encode some data into a specific base64 form when trying to send/upload/post images OR it may need to perform a series of API requests to translate a value/set of values to something specific to solution/service/API being integrated. Inheritance gives us the ability to override the specific method(s) to do this - furthermore we can maintain state much more easily than say if we used composition.
Inheritance has given us the ability to rapidly develop these addins, they are succinct, can be easily tested and are maintainable.
Love your videos, mate! :)
Love your vids❤
Nice vid but is best to watch it at 1.75x ... better for the ears ;)
You’re awesome ❤ awesome 👏
😎
Extremely controversial statements which violate SRP, and decline using of protected/private/abstract methods.
Thank you for supplying an alternative perspective. Would you care to elaborate why you think this is controversial? My argument is not that you should do “two things” in a sense that it would violate SRP. The point is: Both hierarchical reuse of code and subtype polymorphism could be used for the same “feature” or “thing”, and inheritance is only a suitable solution if you need both of those to succinctly implement your one feature or thing. Otherwise inheritance is a worse solution than the alternative (which would be either composition or subtype polymorphism through interfaces). Please do feel free elaborate 😊 Thank you again 😊🙏
I wish you went more into the reasoning behind your advice but i do agree with the general sentiment. I've always had a bad time with inheritance and I'm sure most people have, but i used to question if it's because I'm not good at using it or if it's just not a good paradigm.
I've been avoiding inheritance like the plague for the last year, it's difficult to debug, it's awful for code readability and i spend more time trying to fit my program into the paradigm rather than writing code to fit my program's requirements. I think the times when OOP is actually a good way to solve a problem are much fewer than people realize even today. I think it's almost always best avoided. Composition is infinitely more flexible and doesn't force you to literally plan out the whole structure of your application before actually writing the application.
Humanity went a step back with the misuse and overuse of modern day OOP and i think this calls for a huge moment of self reflection for all of mankind about how we are prone to accepting things as truth because of general consensus.
One exception I can think of right now : sometimes I use inheritance to enforce identicalness across things, for exemple :
Imagine a web application where every UI elements are defined with components called "blocks" (dozensss of them), it might make sense to inherit all different blocks from a parent class ("AbstractBlock" for exemple) even if blocks doesn't overwrite methods from the parent class, simply because when the day comes where you need to implement a feature inside ALL blocks, I would rather edit a single file than edit dozens of them ! (and maybe miss some blocks created in an un-merged branch). Or someone might not know that when you create a new block you need to implement X, Y and Z features. It's a lot less prone to human errors when the only thing to remember is "you need to extend from this class and that's it".
O my, just made this error last week... stupid me
stupid you from last week is dead, long live smarter you of the future :)
hazza > izza)
😆
And then Java goes off and adds "default implementation" to interfaces lol.
"just the fact that we want to reuse code, does not justify the use of inheritance"
Nonsense. The sole purpose of inheritance is code reuse (reuse of procedures/methods), similar to how procedures serve the purpose of reusing sequences of operations. However, inheritance operates at a higher level. The connection between inheritance and polymorphism is coincidental. Initially, inheritance was the sole method for implementing polymorphism. Subsequently, polymorphism acquired its own implementation mechanism known as interfaces.
You've not provided much context, so I'll assert my own: In languages like C# and Java, inheritance does more than just facilitate code reuse. The polymorphism manifesting from inheritance is not coincidental but an intended feature of these languages. As such, having a class inherit from another carries semantic meaning: it implies an is-a relationship; it implies substitutability. When you subclass a class, you make an implied promise to follow its contract. If you never cared about the contract and only about the code, it's easy to (knowingly or not) break the contract, which can lead to all sorts of hard to find bugs in other parts of the system.
Composition is a more basic functionality that doesn't require inheritance yet still enables code reuse. It doesn't carry any unintended semantic meaning and encapsulates the implementation detail of code sharing (fully or partly, depending on whether you inject the component), making the class more robust (you can shield users of your class from changes to the "shared" implementation, maintaining their contract with your class independent of such changes).
this beauty of explanation 😘🤌
great