Inheritance vs Composition - How To Program in C# dotnet
March 27, 2023
• 1,154 views
In this live stream, we'll be using C# (a dotnet language) to look at the object-oriented programming concepts of inheritance and composition. The syntax that we will use is in the C# language, but the concepts themselves will be applicable to other programming languages.
Hey folks! I'm Nick Cosentino, and I'm a Principal Engineering Manager at Microsoft. I believe that programming is one of the most important skills you can have access to, and I'm here to help you get started. You won't need a...
View Transcript
hey thanks for checking out this stream I'm just gonna post a message in the chat here hopefully that goes through in just a sec um just to say that basically I will be trying to watch the chat as I'm presenting so if you have questions comments please feel free to engage there I will try my best to answer during the stream um I have to kind of watch a second screen to see stuff coming in it's slightly delayed so just uh heads up on that and then of course if you're watching the recording of This you won't have the chat available to ask questions but please use the comments I will respond so the topic for today that I want to go over is about object oriented programming and this is going to be a beginner Focus so I'm actually going to spend the beginning
of this um I don't want to I don't want to push it to an hour I'm hoping in about 40 minutes we can kind of wrap this up but I'm going to spend the beginning portion of this kind of just talking about object oriented programming in general introduce the concepts of inheritance and composition kind of compare and contrast them um I will share right now that I do have a bias to not use inheritance but it is one of the things that we're taught pretty early on in programming so just a heads up that is my bias I will uh try to offer some insights as to why that is the case and because this is beginner focused I'm not going to be diving into more complex examples and code that might illustrate that so we'll see how far we get and then the other
thing I'll mention is that when we do get into some of the code depending on how much experience you have at all with programming for some folks that might be literally zero that's okay um there might be some terminology that might not make sense I will try to go very slow explain what I think are very beginner Concepts but if I'm glossing over them again please ask in the chat I will try to pause and just offer a little bit more explanation okay that's my my Preamble so object oriented programming um for me this is something that when when people ask me about programming and you know why I enjoy it or if it's hard or anything else like that I always go back to telling people that I I look at programming as if it's like building Lego except I have unlimited Lego bricks
and I can create any Lego brick that I can think about so the reason that that metaphor really clicks for me is because of object oriented programming so to try and give you a bit of an example here I think some of us when we're learning how to program of course some of the first programs that we write are you know like a simple script or something that just does a couple of operations maybe it's you know we we see the hello world example you're printing something to the console or maybe you're playing around with adding some numbers together it's really simple things now when you extend that a little bit and try to think about reusing that code you want to kind of package it up into something we don't really know what this something is yet because we're still kind of getting you
know introduced to programming we want to package it up to reuse it in other parts of our program or in bigger programs so what does that look like and I think object oriented programming really like facilitates that ability for us so I want to give you a concrete example I'm just trying to make up something off the top of my head if you wrote a I'm I don't know this is tricky if you wrote a program that was like you know you're one of your first programs maybe you want to rename some files in a folder to follow a particular format for example you might write that program and at the very beginning of the program it starts going through file by file renaming things kind of feels just like a a one-time run and it's like a script right you'd go run it does
its job great you kind of forget about it but if you said hey I want to be able to reuse this functionality what you might do is actually take that program and the code for it and you would put it in what we call in a lot of programming languages a class you could put it into a class inside of a method for that class and then be able to call that and reuse it so the class the word class is like an object that we would be able to reuse in our code so this is kind of like a really basic intro to it but there's a couple of different flavors or two primary flavors I think that we see for this and that would be inheritance and composition so I'm going to start by explaining briefly what inheritance is and then briefly what
composition is spend a little bit more time on inheritance and then kind of the the same thing for composition so when we think about inheritance as the as the name implies um it's uh designed to be able to inherit right functionality from an ancestor so a lot of the time in programming we are looking to essentially minimize the amount of copying and pasting of code we're doing so if you have functionality that works in a particular case and you want to have that same functionality somewhere else instead of just copying and pasting you know maybe 10 to 100 lines of code or something duplicating the whole thing you might have it in an object and you might be trying to do that to reuse it now when we have inheritance what we're able to do is put some functionality characteristics or properties into an object
and we would call that let's say it will be our ancestor or our root and then what we could do is actually inherit so have another class that inherits the functionality of that base class or the ancestor and then actually access that functionality and not only access it but depending on what we're doing in inheritance we could modify it we could override it we could tweak it in some way and kind of make it our own so you can keep extending this functionality such that the more levels that you have in your hierarchy the more like layers of customization that you can make to your original object I'm going to briefly jump to composition and then I'll come back so composition is almost the opposite of this in terms of how you organize things so instead of having a hierarchy where you would say I
want one root object and then I will inherit to sort of extend the functionality and reuse it instead you make many small objects each of these small objects is mostly purpose built right it will have a particular functionality kind of very specific to this object itself and then you use those as building blocks for larger objects now again the difference is that you are making objects like more complex objects out of smaller ones right and then you can keep extending that pattern such that your complex object with another complex object could be used together in yet another more complex object so it's kind of like I would think about it like wrapping things around objects and inheritance is sort of this hierarchy okay so let's maybe think about a couple examples here and then um I might try to jump over to code we're almost
10 minutes in so it might be a good time just to actually start looking at something so when we talk about inheritance maybe an example um two that come to mind that that work pretty well I think for non-programmers to kind of relate to this concept or if you're a beginner programmer programmer it might make more sense um animals so animals inside of programs maybe that's a little bit of a weird concept but just to demonstrate what inheritance means if you had a class that you wanted to sort of Define functionality and characteristics for an animal you could create a class that was called animal and then you might introduce a couple of properties or functions that you you expect that animal to have so for example um you know all animals might have a a function that says eat because every animal will eat
and all uh you know that that same class might have a function function that says reproduce right because all animals should be able to reproduce and maybe it has characteristics like the color right I'm really really simplifying this because an animal is actually a a pretty complex thing but you might have color you might have weight just some properties that Define that and the idea is that these functions and properties that you're putting onto your animal ancestor class these are actually things that more specific types of animals would inherit okay so if we have that where do we go from here well you might be able to say then okay well I want a mammal or I want a reptile so you could introduce a class for a mammal and a reptile that inherits from animal right because both mammals and reptiles are animals and
then from there you could actually access some of the functionality right like eat reproduce but you might want to actually be able to override some of the other characteristics now I'm not going to get into the biology of mammals and reptiles I actually recorded a video on this already and messed up mammals somehow which is pretty embarrassing but the idea is that maybe um like reptiles you could talk about the type of um you know the type of skin that they have so you could override some characteristic that was from animal and talk about the skin there and for for mammals maybe um there's some functionality or characteristics we could override for for something to do with like body hair and and things like that so from there because that's just one extra layer in the hierarchy you could go yet another layer and spoiler
alert you can keep doing this with inheritance but for mammals maybe you want to do like a dog class or a cat class and then from there another level could be the the breed of the dog or the cat and you can keep doing this and you end up getting to reuse the functionality from the more ancestor classes and you can override or tweak and tune those characteristics or functionality in the child classes so I think a lot of the time like people are taught this very early on an object oriented programming and personally I think that it sticks with people because we have so many of these examples that are like real world like you can relate to it I think the animal one's pretty good I think vehicles are another interesting one because you could even talk about like um you know like
Transportation type and then you could have like um car truck or boat or plane and then you know like bicycle you could have all these things that kind of inherit and then like a hierarchy that you build out of it but let's jump over to composition because I think composition is is the thing that I do want to spend arguably a little bit more time just explaining because I think that there's more benefit in understanding it because long term I think that's what people should be focusing on again I tried to call out this bias a little bit earlier so I mentioned composition is about putting objects inside of something else to make a more complex one and I like using vehicles for this example because I think that something like a vehicle is actually a really good way to think about something physical from
The Real World where this concept really makes sense so if I said we want to have a vehicle class in The Inheritance example you might say okay we have a vehicle and then we want to inherit from that to have a car or inherit from vehicle to have a truck and then from there you could have like the the specific models of cars and trucks and and that kind of thing and if you continue that thought process you might say well then we want to override the the functionality for like how fast it goes like how much how fast it accelerates the fuel consumption so it seems like it's pretty easy to apply The Inheritance part but composition I think really works here because if I said I want to create a vehicle well what goes into a vehicle well there's a lot of things
that go into a vehicle and I am certainly not an expert I love cars but I'm not going to try to pretend like I can name every component that goes into a car but just to um to think about a more simplified version of this if you were to create a car some of the pieces that go into a car you might say Well it needs seats okay so that's one of the type like one of the objects that would go into a car and you can say how many seats and then a car also needs an engine okay and maybe a car will have a spot for a spoiler I don't know think about your if you play racing games think about some of the things that you can modify like a car will need brakes right a car will need wheels so you
could go create your vehicle class and instead of inheriting from vehicle you would start passing in other objects that make up your vehicle but this chain that I was talking about from inheritance you can have a similar um sort of approach for your um your composition pattern so what do I mean by that well I mentioned engine for example now if you're thinking about the the engine of the motor in your vehicle that's also an extremely complicated thing right it's not just like a a simple like we wouldn't have a simple class that defines that in code so you take that same approach and you say okay if I want to now make an engine what goes into that okay well you might have rods Pistons you might have properties that Define the type of material right so you start passing in all this information
as smaller objects into your engine so if you can kind of conceptualize this to use composition we need to First create all the small little pieces and then start packaging them up and then put those into more complex things so now I'm about 15 minutes in and I think we'll jump over to code now so I can start showing you what inheritance would look like we're going to use C sharp and then I'll show you what composition looks like as well and I will try to wrap up by giving you a little bit more context still try to be beginner focused on why I truly think that you want to spend a little bit more time trying to understand uh composition over inheritance so give me one sec here I will switch over to net fiddle um if you want to play uh like follow
along in your browser and play along um you can check out the URL that I have um in the screen that I will be sharing in just a sec it should be showing right now with my face on the top right corner and yeah so you can see.net fiddle.net up at the top here the code that I'm going to be writing isn't going to be anything spectacular so um you can probably just if you want just watch or you can follow along and try things out so C sharp is the language we're using and C sharp itself is an object-oriented language and one of the the things that is already interesting this uh the code that's on the screen here I'll zoom in one more time the code that's on the screen here is basically the the very first pro like I didn't write this
it just kind of shows up on the screen it's actually like the hello world program right so it's one of the first programs that people write and in C sharp you can already see that it says public class program you heard me say class earlier and it's because in C sharp a class defines an object so going back to C sharp being a object-oriented language even our program like where our entry point for our program is is defined inside of an object and that object is called program so just a little a little tip there just so you know okay so I want to start with inheritance and to do inheritance I think I want to uh actually I want to try using a similar example for both inheritance and composition so let's stick with vehicles because I think that Vehicles will probably be a
little bit easier when we get into composition but let's go ahead and start so in inheritance we want to Define our sort of like our ancestor or our Base Class so I'm going to start with vehicle and you can see that all that I'm doing here is I've uh kind of like how we head for program I just have a class that is named vehicle the public part you don't really have to be concerned with that that's just um how visible this is for other people to be able to see so not to really worry but this part here is how we Define a vehicle and inside of the curly braces we don't have anything right now so that means that our vehicle doesn't have any property so no characteristics and it doesn't have any functionality defined by any methods so right now our vehicle
doesn't do anything at all pretty boring but just to show you how inheritance looks I'm going to copy and paste the vehicle and I want to have a car but a car is a type of vehicle it inherits from vehicle so by using this syntax here the colon and then vehicle after the word car this tells us in C sharp that a car is a type of vehicle and I'm going to do the same thing now for truck again as I'm doing this just see like to to point it out again there's no functionality yet I'm literally just assigning some objects that have a hierarchy to them so um hopefully this makes sense this syntax again if you're not familiar with it that's okay but we have now three classes on our screen the vehicle is the like the topmost ancestor in this hierarchy then
cars inherit from vehicle and trucks inherit from vehicle as well now you could do another level of let's say uh of car so I want to have a type of car well I want a I want a Lambo everyone wants a Lambo so a Lambo inherits from Carr which also inherits from vehicle right so to to kind of think about this you'll like again Lambo inherit some car it does not inherit from truck so a Lambo is not a truck a Lambo is a car and it is a vehicle so hopefully that makes sense um I don't really know many trucks but you could basically do the same type of thing and inherit from truck with your own type of specific model of truck okay so we kind of just chatted through how the hierarchy works and how we actually inherit but what do we
want to do with that well let's go ahead and maybe introduce some functionality and some properties so we could have something like um we could have I don't want to this might make it a little bit more complicated so I apologize but when we talk about the data types that we're going to use I'm either just going to use booleans so true and false strings so words or integers or floating Point numbers just so we have some numbers just as a heads up because what I was going to do is say color there is a data type for color I'm not going to go using it because it's going to get kind of messy so we'll just have color so you can have a vehicle so every vehicle because it's a physical thing might have some color associated with it Okay now what's interesting about
this is that if we think about color color doesn't actually change based on the type of vehicle that we have right so that might not make a lot of sense in this example but it's a property that exists on a vehicle what about um the weight right so we could say public float for a number um wait in kg now okay this is probably the same issue right the weight is not actually going to be assigned by whether or not it's a car or a truck or a Lambo right these are just characteristics that exist on a vehicle okay so how do we make this feel a little bit better how do we start looking at like what differentiates a car from a truck well we could say that maybe by definition all trucks have beds on them okay so what we could do is
we could do public float fed with them sorry the microphone's right in my face and I can't see my keyboard as I type bed with and bed length so what's interesting here is if we were to look at what properties a truck has a truck now has properties that Define the bed of the truck right but because it inherits from vehicle a truck also has these two other properties and that's because we said every vehicle will have color it will have some weight in kilograms um it will have a width and a length for the bed for a truck but car and then by definition Lambo will not get these two properties and that's because the way that we've defined what a truck actually is these two properties will never exist on a car and unless you wanted to make another subclass of some maybe
Frankenstein Lamborghini you're also not going to have a bed on your Lambo so there's one super quick example okay now you can keep doing this type of pattern where we could go look at well what makes a car unique and then you could say well what makes a Lambo unique but let's talk about functionality okay so let's um this is going to be really contrived so I apologize I just want to kind of show you um what you're able to accomplish here so we might have um like every vehicle should be able to drive hopefully right if it's running so you could have methods on here like start the vehicle stop the vehicle accelerate decelerate that kind of thing steer so like you know turn left turn right I'm just going to really simplify this to say drive just to keep this example short so
public void Drive okay so what's interesting and I'm again I'm saying this is contrived because I just want to be able to demonstrate some other language features here and heads up these language features that I'm going to talk about are in C sharp but the concepts are certainly applicable to other programming languages it's just the terminology might be slightly different okay so every vehicle should be able to drive but because I put this method drive right in the ancestor class vehicle it now requires me to be able to say how it drives well in the ancestor class vehicle I actually have no concept of what we even have to work with here so instead of actually defining this function like this what I could do is say look in the Base Class like in the the most ancestor class I don't know how to drive
I know that a vehicle should drive and it must have that functionality but I don't have enough information to say that other people have to Define that for me so then we can use this keyword called abstract here and then what that means is that we have to make the class itself abstract okay so this might already sound super confusing but what this will mean by using the keyword abstract is that in our code we can never write the following syntax we can't say vehicle my vehicle equals new vehicle we can't do this because a vehicle is abstract if I took this part off it would allow it so we can't make new instances of vehicles but we can make new instances of the non-abstract classes so if I wanted to make a new Lambo that would work because a Lambert a Lamborghini in our
example is not marked as abstract so just again to repeat a little bit abstract is a keyword that suggests to the compiler that this class is sort of not complete it is a base class it's a piece of what we need but we need to have another class that inherits from it to be able to actually use it okay so now that I've done that you can see car truck and Lambos fine but car and truck aren't in good shape we have an error and it says that car does not implement the inherited abstract member Drive okay so we can actually do the same thing and Mark this one as abstract and this as well so what what's actually happening here so what I'm now saying by having car and truck also marked as abstract is that the three things vehicle car and truck we
can never put any of those things here we can't just make instances of vehicle car and truck we have to make specific implementations for each of the models of these that we want to use and that's why Lambo if I could type it Lambo will still work for us here but there's a problem because now Lambo also does not implement this abstract member Drive so what we could do is we have to say public we have to go Implement Drive and again because I said this is going to be super contrived we'll just say we'll just write to the console so it'll show up down here where it says hello world I'll just say Lambo goes fast and now in my program I could say my myvehicle dot Drive oops and if I run this hello world and then Lambo goes fast so not super
exciting but just wanted to show you that that's what abstract does and then when we actually go to implement it we can override that functionality and in fact Lambo has to override that functionality because it's not abstract anymore and we will put this implementation in we can make a slight adjustment to this just to show you something else that's not abstract it's another flavor of it and it's called virtual so what I will do is instead I will leave this one as abstract so that won't change but I'm going to make car and truck actually not abstract now now that means to make the compiler happy it needs to implement the drive method and we can go do that I'm just going to copy and paste this just because I'm super lazy and I don't want to mess up my typing so we can go
do that but this this of course is now incorrect I need to say car goes at normal speed right I don't know and then maybe trucks are slow sorry if you have a fast truck I know not all trucks are slow but um so if I go back up to the top here I still can't put vehicle here right because vehicle is abstract we cannot make a new instance of it I can put car here and if I go run this car goes at normal speed I can put truck here truck goes slower and if I put Lambo Lambo goes fast so this Behavior I talked about at the beginning right when I was talking about this inheritance hierarchy and was saying that we get to inherit the characteristics and then we're able to either inherit the methods that we have or using some keywords
we can actually override and change that functionality to make it our own so hopefully that makes a little bit more sense there's another word just in case you're curious It's not abstract it's called virtual so I will before I jump over to composition I'm just going to change this class from being abstract now and this is going to be virtual so because this is not abstract anymore yes we will be able to make an instance of this and we could say that the default I would never really recommend you programming like this by the way I'm just trying to illustrate an example um we could say that when you try to drive a vehicle class and we don't have any other any other information what foreign we could say like what vehicle do we even have right because like I said at the beginning that
we don't even know how to drive the vehicle if we don't even know what it is so this is just to show you that virtual allowed us to still override here it allowed us to override here and it allowed us to override here so quick recap we were able to inherit from vehicle we got to see what using the abstract keyword did we got to see what virtual does we could see some examples of basically introducing new characteristics to child classes and then overriding some of this functionality based on what we have here then we saw that when we actually called this stuff up at the top you'll if you're paying attention you'll notice that this part never changed so I have high what I have highlighted so anytime I had vehicle if I had Lambo here I can actually assign a Lamborghini to a
variable of type vehicle because a Lamborghini is a vehicle it is a car as well oops right so this should also work right no errors okay now I'm about 35 minutes and I want to try jumping over to composition I was hoping this wasn't going to go a full hour so I do apologize let me go ahead and get rid of all of this code we will start fresh with composition so I'm sticking with vehicles so let's go ahead and put vehicle back just to prove a point I'm going to use this sealed keyword here sealed means that we are not allowed to inherit from it this prevents inheritance we don't need it I'm just using it so that you know I'm not cheating in my examples and we will not inherit from vehicle and still try to get some examples going here where we
can build up a vehicle okay so early on I said that when we use composition it's kind of like taking smaller pieces and taking more simple objects putting them together into a more complex object and then repeating that process so I was really bad at kind of listing out the things that go into a vehicle but let's have another stab at what that looks like so I said that we could have things like seats oops so we could have seat I might want to have I'm just trying to think about I mentioned earlier like thinking about racing games and the things that you can tweak on your vehicles so the different breaks we have um you might want to Wing Wing or a spoiler you could have engine so these are just a handful of things but we want to basically pass them into our
vehicle because our vehicle needs to be made up of these smaller pieces so I'm gonna make one more small adjustment just to show you another language feature that we have in C sharp It's relatively new it's called a record um in our case here a record is just going to be like a class but it's going to let us make this look a little bit less gross so I want to pass in like I said the pieces that go into making a vehicle so I need an engine so it will be um this is the type and then this is the name of the property and then I need to have breaks so um on let's say that for some of these things that our vehicles can have multiple seats they can have multiple brakes to get a One Wing a one engine you're free
to do whatever the heck you want I just want to be able to show you multiples so we could do like an array of seat to get seats we could do an array breaks and then we would do like a wing okay so when I do this just to go back up to the top here and show you how we would go make a new instance of this vehicle we would say um vehicle my it's surprisingly hard to type when I can't see my hands so new but we can't just do this we need to pass in all of the things that go into vehicle and fortunately we have that list right here so we'd have a new engine we need a new array of seats so let's say that in our vehicle it's only a two-seater so I'm going to one seat there's two
seats boom two seats inside of an array what's next we need brakes well we're going to have two brakes on the front and two in the rear so another array for those that aren't familiar this syntax here with the square braces this is just how you denote that you're creating an array so new right so I will do that and put four of them in because we need four breaks for our vehicle and then the final thing is the wing because every cool car has a wing right okay and it doesn't all fit on this on the screen I can't I can't adjust the size of this uh I can zoom out a little bit there we go hopefully that's still uh legible for you folks but you can see that vehicle it's a lot more verbose when we're declaring it and making a new
instance of it but we don't have any inheritance hierarchy to be able to do this so something that's kind of cool um it's just a slight tangent for what the record type is it's I mentioned it's very much like a class it just gives us some other built-in functionality that's kind of nice for what I'm about to show you here so I can actually print out what that record looks like and it's a little bit more uh readable than a class would be by default so if I go run this um you can see that it says okay we have an engine now this part looks a little confusing it says program plus engine um that's my my bad let me go ahead and just I'll rerun this in just a second I'm going to move all these things outside of our program class recall
at the beginning I said that we are all inside of this program class so I'll just pull those out oh my goodness the tabbing there we go I'll run it again okay now it's a little bit more readable you can see that we have the engine is set to be an engine the seats it doesn't show you how many that's just the limitation of this of the record kind of printing out to the console but we have an array of seats we have an array of breaks and we have a wing Okay cool so this part seems probably super boring because you're like well that's nice we can just keep listing off the things that need to go into a into a car or into a vehicle right but now I want to show you instead of overriding things how we can change the functionality
um and this part to me is super cool because you can basically remember my my analogy at the beginning was like Lego bricks you can go make anything that you can think up so if you're familiar with playing with Lego if you've ever tried to build something out of a set and then you took it all apart and you said I want to make my own stuff and you start building something up and you're like oh man I wish I just had some peace well now you can so we have this engine it's kind of boring it doesn't actually do anything right so um I mean none of these actually do anything but what you could do is we could maybe just to make this a little bit more interesting I'm going to show you another couple of things I'm trying to be cognizant of
time here I'm going to introduce our first interface and you might say well that sounds scary what is an interface um an interface is sort of like abstract classes that we saw earlier except it's not a class it just defines this um sort of like the literally the interface so um the characteristics or the methods that you should be able to see on an implementation but it is not an implementation it does not provide any functionality by default whereas an abstract class is able to do so so we could say that an engine I'm going to again use some really simple properties here might have something like float displacement in leaders and then I want to do like um we'll do an integer for number of number of cylinders okay then I will actually make this we're going to make two different types of engines
here so the engine that I have in my car is an Audi TT so the engine that I have just to make this a little bit more explicit here I need to have this part to say that my class Audi TT engine must inherit from I engine and you'll notice that it says it doesn't Implement these two properties that's okay we'll just go put those on and it needs to have public that's a requirement for an interface and then we have to actually provide some values here so I have a 2.5 liter and it is a five-cylinder kind of weird um just looking here what's oops my goodness it wasn't a string there we go and I'm missing a semicolon okay and then we could say my fiance drives our AMG GT and I don't know what the displacement is in that I should probably
know nine thousand um it's not obviously but it's an eight cylinder so oops what I want to show you is that we can actually go change we can go change the vehicle entirely and just swap out the engine by having two different implementations here so we'll start by putting the Audi TT engine in sorry I forgot I need to change the syntax here because this needs to say I engine now if you recall I just introduced that interface so I need to pass that interface in so an Audi TT engine does implement that interface which means we can use it here if I press run you can see that the engine is an Audi TT engine and then if I wanted to afterwards I could go right out specifically what the engine is and it says Audi TT engine ah I forgot I'm using classes
my apologies let's go back to record will that do it there we go okay so I don't even need to have that second print line again I'm using records just because when they print to the console they're formatted a little bit more nicely so you can see in this example then why by passing in an Audi TT engine into the vehicle that we get oh my goodness I can't spell displacement supposed to say displacement of 2.5 liters right and the number of cylinders is five but if we wanted to go and this is where it gets a little bit unrealistic for vehicles but if I wanted to go swap this to be the AMG engine what did I call it let me go fix this too that's going to really bother me so I'm gonna go take that I think that's incorrect now okay one
sec there we go what oh I missed this see this is why sometimes using these uh online editors is not helpful you missed too many things but what I was able to do is just Swap this out right now I have an AMG GT engine in my vehicle it is way bigger way more cylinders awesome so we can completely change functionality of a vehicle by swapping the pieces inside of the vehicle we don't have to inherit and then override things to change them so hopefully these examples made sense but you might still be sitting there going well Nikki said at the beginning that you don't favor inheritance he said that um composition is sort of this better way to go and why because it still might not be obvious why we were able to actually accomplish very similar things with both of them so why
would it be better to use composition over inheritance okay so in programming this is where it might get a little bit more um I guess complex so instead of me diving into the actual code to show you I'm just going to talk about um you need to kind of conceptualize this so I might kind of jump back to just my face so I can talk with my hands a little bit better Okay so when we're talking about composition I mentioned and kind of Illustrated that we're actually taking small things taking a handful of small things passing them into a more complex object and we can kind of keep repeating this in programming when we want to be able to test things more effectively um we and basically have more flexible code more extensible code it's a lot more beneficial to have smaller more purpose-built objects
or classes because they're able to isolate more functionality and then we can focus on that so just to give you an inverse example if I had a program that was one method and a thousand lines of code if I wanted to exercise any part of that program I have to go touch one method that's a thousand lines of code that means I would have to go basically run through the same same set of instructions to try and get to a point just to exercise it if I wanted to change part of that program again I'm going into the same thousand lines and potentially messing something up now if that program was instead split into smaller pieces what I could do is I could go write test coverage on pieces of this code right when I go do that and write tests on the pieces when
I have to go change something I might be going to touch one of the pieces and in theory that should tell you that if I've touched this piece over here somewhere and I didn't touch this piece over here you shouldn't have to go test this other thing you should feel confident I touch nothing to do with this I touch this thing let's go run tests for this thing now you can kind of keep extending that concept because when you have all of these smaller more isolated pieces not only are they easier to test but because they're isolated they kind of give you this boundary where you don't have to go test your entire system you don't have to lose confidence in your entire system kind of falling apart now with inheritance why this does not really work because you might say well Nick all isn't
all that stuff in the base class right that's uh that's a smaller thing it's in the base class we should be able to test that now yes but I showed you and this might not be obvious which is why I was saying slightly more advanced when you're going to test some of this stuff I showed you earlier that when you have that abstract class at the base you can't make a new instance of it so to go test that there's not a lot of tools that make that easy to test and generally what you have to do is go test some implementation that inherits from that abstract class so that would mean that in our example from earlier we couldn't test the functionality directly in the vehicle and at some point because I made car and truck abstract we couldn't test the functionality directly in
those I would have to go make a Lamborghini because that was the class that I had that was not abstract just to be able to test the functionality in those base classes so in my example it was very contrived because these are really simple objects but when you start using abstract virtual and overriding different methods different characteristics and your inheritance hierarchy gets really deep it's actually very difficult to isolate some of the things that you would like to test in your more like ancestor type objects and in fact it can make it really difficult to test things in your child objects because if your ancestor stuff has to execute a lot of code before it will even call something that your child class can override you don't have a choice but to set up your test such that the whole body of code in the
ancestor can get executed before getting to your small piece so long story short there inheritance generally does not lend itself well to isolating code to being tested another quick note is that and sorry I don't mean to like totally bash inheritance it's just that when you see these things kind of get out of control after many years um there's a lot of examples where just uh it's people people didn't pick composition probably because they weren't familiar with it so another example though is that that way I'm trying to think of a good way to put this um okay so when you have really big inheritance hierarchies in my example I just showed a vehicle then a car and truck and then we had a Lamborghini below car so only a couple of classes If instead instead of just having that we had I've seen literally
inheritance hierarchies that will have hundreds of implementations if you go make a change in one of the and like when I say hundreds of implementations I mean that could be hundreds but also spanning you know from two to seven or ten layers deep in a hierarchy so um imagine how complex that might get and I'm not exaggerating when I say hundreds either if you were to go change some of the functionality in the root in one of those more ancestor objects if you go change that you now have a cascading effect it's the exact opposite from composition where it was isolated you would have a cascading effect that could basically potentially affect all of your child classes it's not necessarily isolated so when it comes to testing how would you prove that you didn't just go break all of these things sometimes you can but
a lot of the time that's not the case if it's shared code it's one part the other part is that if you were to change sort of like the signature of one of these abstract classes or like an ancestor class right if you introduced a new abstract method or property all of a sudden everything in my example that I was just mentioning like hundreds of classes would instantly break not compile you would have to go add a property or a method to all of these just to meet your new signature so I don't want to tell you that you cannot use inheritance but I would strongly encourage you to limit the scope of how you're using it I don't think that you should design entire applications where you have large inheritance hierarchies and I would strongly encourage you to think about writing smaller more oops
my mic smaller more purpose-built classes right think about how you kind of group a few of those together wrap them in a more complex object and keep repeating that process I can I would probably bet money if you take that approach you will find that more long term in your software engineering Journey you will find that code easier to test you'll find that it will be more flexible and I think you'll have a more enjoyable experience so just wanted to share that because I have been guilty of graduating from University in computer engineering going into my first full-time job and changing everything to be an absurdly big inheritance hierarchy and a couple years into it being like Oh my goodness what have I done and it's because I did not know better and I'm just trying to share that with you so we'll wrap all
this up it did actually end up taking the full hour I apologize but we did look at inheritance we did look at composition inheritance allows you to in as the name suggests inherit from more ancestor classes to to gain functionality right to be able to reuse it you can override it depending on how your structure is set up and composition is just the inverse of that where we don't inherit from things but we make objects based on more simple objects passed into it and just to summarize I do think that composition will lend itself better to your software engineering Journey so if you're not familiar with it still please do read more about it try to focus on that and I think that'll work out for you in the long run awesome so thanks so much for tuning in if you thought this was helpful
uh please go ahead and subscribe I try to do these I want to get to about two a month I'm doing one right now I want to do one beginner one and then one more advanced one um and we'll see how that goes so again thank you
Frequently Asked Questions
What is the main difference between inheritance and composition in object-oriented programming?
The main difference is that inheritance creates a hierarchy where a class can inherit properties and methods from a parent class, while composition involves creating complex objects by combining simpler, purpose-built objects. Inheritance can lead to tightly coupled code, whereas composition promotes more flexible and maintainable code.
Why do you prefer composition over inheritance?
I prefer composition because it allows for more modular and reusable code. With composition, I can create smaller, focused classes that can be easily tested and modified without affecting other parts of the system. This isolation helps prevent cascading issues that can arise from deep inheritance hierarchies.
How can I get started with using composition in my C# projects?
To get started with composition, begin by identifying the smaller components that make up your larger objects. Create classes for these components and then combine them into more complex objects. Focus on defining clear interfaces for each component, which will help you swap out implementations easily and keep your codebase flexible.
These FAQs were generated by AI from the video transcript.