Not a fan of foo and bar. To a beginner, they look like some obscure function or keyword. Animals are a much better subject in this regard. Also don't like "my" classes, something just doesn't sit right with me about them.
@@2bfrank657 I agree the "my" classes aren't very descriptive but one thing i do like about those examples is that they imply they are an identifier, meaning it is named by the programmer rather than being a keyword. Not too useful for any topic outside of the basics, however.
Yeah the problem with those examples they use is that it's only useful to people with the lowest level of understanding. And that level is certainly not where most programmers struggle.
Also the problem you try to solve is to break down complexity. Not just to understand the mechanisms, but why these mechanisms are the best approach. With 'animal' examples you don't hit that type of complexity. And specifically: The biological tree of life does not have the same properties as a good class hierarchy. And prevents good understanding.
Same here. 9/10 articles they make these bare bone, unrealistic examples and call it a day, and I have a hard time then translating it to real world situations.
It's truly unbelievable, in 30 days with 4 videos, 100K subscribers. I have never seen anything like this before. Excellent work, keep going with these small but crucial programming details.
@@eckligt TIL. On Wikipedia, it shows the separate letter pronunciation. Oxford dictionary also shows the individual letters. Everyone I know says the letters individually lol
I've always known it as png since I was a kid and first encountered it. Born in 83 for reference. Also, "gif" is pronounced like the peanut butter "jif". "gib", an old term from gaming that I shan't tell you what it means (we don't want kids changing the meaning) is pronounced with a J sound at the beginning... And that comes from the famous developer that made the word popular.
This channel is quickly becoming one of my favorite programming-related channels. I'm sure I'm not the only one who appeciates the clear explanations coupled with beautiful animation - It's like 1brown3blue for programming.
I've found that tight interfaces with default implementations have provided a really nice balance between minimizing common business logic and preventing tight coupling when you lean on multiple interface implementation. It allows you to mostly lean on composition (implementing the interfaces you care about) while gaining some benefits of inheritance (common methods have a default implementation to reduce code reuse)
I've been programming for over a decade and these videos explain things I already know or thought I knew in ways that make me question some of my own designs over the years! Thank you very much! I always feel like I come away from your videos with something useful to think about.
EIther I am too demanding on, and/or too expecting from my subordinates to improve themselves and know all of this, or you lack a lot of knowledge, if you do not design code like in the "good" examples in this video automatically after over a decade of programming. Everybody on my team, even people with less than 3 years of experience, is taught technical architecture through conventions and prepared documentation.
@@Ondraasha What is the point of slamming some random dude praising the video? Also, why do you write 50-word sentences? Either I am too demanding on, and/or too expecting from my subordinates to improve themselves and know all of this, or you lack a lot of knowledge, if you do not design sentences like me in the "good" previous two sentences I made in this comment automatically after over two or three decades of speaking English. Everybody on my team, even people with less than 3 years of experience, is taught technical sentence structure through conventions and prepared documentation.
Java really popularized inheritance based programming, and it WAS the go-to paradigm for a long time. Only recently has most of us come to terms with its inherent issues. I don't blame people for using inheritance, I've done it myself a lot. The past is the past. Instead we should focus on the future. We will never stop learning and improving unless we give up, and we need to come to terms with that reality that what we did before likely _IS_ flawed.
@@MrMudbill Yes, Java, PHP, and Javascript are the real offenders here teaching hundreds of thousands of developers to stick with OOP Inheritance. Learning and writing Rust, Go, Lisp, and many other languages helps expose people to better ideas.
This is by far the best explanation of the topic I’ve ever seen. Not overly complicated, but what’s even more impressive - not unnecessarily dumbed down as well. Fantastic content.
In game development the most common composition pattern is called an Entity Component System (ECS). You pay a small price in object creation & destruction, but you gain optimal memory access and incredible flexibility! It’s not immediately applicable to other disciplines of programming, but I’d still highly recommend it to everyone. It’s like the game development version of dependency injection.
ECS has gained popularity later, and is not a magic silver bullet. Game Dev is still a heavy OO world (opposed to ECS, which is data driven) where a lot of Inheritance is used along with composition
@@neonbyte1337it's not about whether vtables are fast or not, one of the main benefits of ECS is that components are sequential in memory, meaning you heavily reduce cache misses and keep your cache full of the data you're going to be processing. It's excellent for quickly and effectively processing lots of elements, and having your data layed out as POD and also sequentially makes multi threading much more convenient to manage.
This is quickly becoming a top favourite coding channel of mine. The topics are explained wonderfully and I love the visual style. Each of these videos are so easy on the eye, easy to follow, and quick to understand. I think it's because you're to-the-point, you're demonstrating what you're talking about, as you're talking about it; and you demonstrate the importance or usefulness of what you're trying to teach, all in a way that looks beautiful. I look forward to more, they're a joy to watch.
You have no idea how long i search for content like yours, as a self taught coder, i had been watching many programming language tutorial explaining about what is variable, for, while, do while, if statement boolean and many others basic programming concept. but ALL of them never bothered explaining the next crucial step between the basic and advance which is how to design your code structure. everyone can write code that a compiler can understand and compiled so the program can run... but not many people can write code that does what i said before AND design the structure of the code CORRECTLY. in fact, i had never see any website or UA-cam programming tutorial taught how to design the structure of the code in the most efficient manner... it seems that you have found yourself a niche in Programming Tutorial UA-cam Channel. and for that sir, you deserve a subscription.
I would love to see a channel like this explain to the broader community the concepts of SOLID and other principles. So wide is the gap between bad and decent code, and simple strategies to mitigate code smell and technical debt would do many wonders!
@@3_smh_3 Single Responsibility make code both easier to read and easier to maintain. It reduces decoupling and reduces the opportunity of code smell. By that alone, code can be objectively better. Open close principle allows for code to be maintained through less need to couple code. Thus, any change to project requirements requires less code refactoring. Liskov subscription is literally "good adhoc polymorphism". It allows you to do things such as dependency injection. Interface segregation means clients do not need to require more than the required interface, as seen in this video (though, composition can be better) Dependency inversion is similar to injection. Except, it is the principle upon relying on the abstraction rather than just moving code to somewhere else. This is all to say that I VERY much disagree that it is bad to know and employ. It should be second language to a dev, and employed to the appropriate degree in a project.
The problem is that the difference between good and bad code is big and small at the same time. Big because you need to know how to do it and why, small because you will be typing the same or even less code to get the the results you want.
@@PereViader Code smell is a vast topic indeed, but design principles were coined and employed for a reason. Much like how design patterns were developed to solve common problems. The help reduce the several kinds of code smell and maintain better code. Edit: oop I misread your words
@@3_smh_3 That's fine. I mean, they're just a collection of best-practices, really. I feal that SRP in SOLID is the most common and enforced, since it follows from basic code habits, such as self-documenting code.
I'm a firm believer of "Best tool for the Job". I use Inheritance, Dependency Injection, and Interface Composition intermixed in the same code base. It is important to understand that each of these things are just tools that each have pros and cons, and they can all easily cohabitate in the same code base. Saying "don't use inheritance" is an inappropriate hardline, and inheritance has very strong uses. There's also Default Implementation for interfaces that has been introduced in a lot of modern languages over the last few years which has been excellent. It provides a way to leverage interfaces as a way to perform composition without having to do direct inheritance.
@@atlantic_love What are you talking about? Learning to use the best tool for the job is like the lesson at the core of software engineering. It is beyond "Useful"
@@atlantic_love Are "Inheritance", "Composition" and "Dependency Injection" the big words? If so, they are "Design Patterns"!. They are a way to structure code following some rules which are supposed to make larg codebases more mantainable and easy to scale, you can learn a lot about them online, and they are used all the time! The names might be complicated, but they are very easy to demistify. Refactoring Guru is a great free resource for example The OP is making a comment about a general rule: "Composition Over Inheritance" associated with these design patterns (Originally coming from the flus Gang of Four book). And saying how this is commonly repeated outside of this context. Making new programers think inheritance is bad. While, in reality, inheritance is just a tool. And while it might not be the best tool for every job. There are a lot of jobs for which it IS the best tool. Having this knowledge in mind is, in my opinion, VERY useful. Specially for programers new to OOP
@@atlantic_love If you were unable to understand what I am saying, that's completely ok as a novice programmer. I did use a few technical terms, which if you stick with a career in programming you'll come to learn. But it's not nice to say that because I used technical terms in a comment to a technical video that I'm "not saying anything useful". I have a made contradictory argument against his hard-line "Don't use inheritance" stance. If you don't agree with my point of view, that's fine and feel free to express your own opinion on the matter.
@@atlantic_love you either did not watch this video, or did not understand the point they were making. The video makes the argument that inheritance should be entirely avoided due to its flaws. My counter argument is that Inheritance should not be avoided but rather embraced when it makes sense, hence the "best tool for the job". If you're not going to provide any helpful insights or opinions to the conversation, then this entire issue you have with my original comment is moot.
So there are concepts that are either: 1. I understand them well enough already I don't feel especially compelled to continue researching them or 2. I know they're a gap for me, but I've tried to understand them too much without real payoff, and I've just given up on pursuing those topics. This channel consistently advances my knowledge in both categories. This video would be an example of the 2nd. Really fantastic work here.
This video is great. And it makes me thingk how real world problems are what really make you learn. If you learn this composition like in university lectures, they'll use examples like Animal, Foo, Toto... you may understand maybe on those examples but you'll never get it at 100% and this video is the proof. Getting involved is the best way to learn stuff, directly to the real parts. Amzing video btw!
I did something similar recently where I wrote a trait based rust composition pattern but realized there was a common structure across all implementing classes. I made the code more succinct by creating an "optional inheritance" with its own blanket implementations so for the 99% of implementing classes you can just inherit and get the traits for free and just implement the last trait needed for integration. What makes this optional is that you can just derive the traits that are needed for the framework (requiring implementing the otherwise blanket implementations yourself) and not inherit the "helper" parent class. That way you get the best of both worlds.
I don't know if you actually read my comment on your video "Abstraction Can Make Your Code Worse", but this is 1) so much better by not making the choice for the viewer, instead clearly stating your opinion and allowing them to come to their own conclusion and 2) an amazing companion video to the discussion around abstraction as a whole. I'm looking forward to the video on Dependency Injection, if for nothing else than because of the great quality of material and informational topics you've covered. Keep growing, and I look forward to the next topic.
I love the way you showed code as you explained the concepts, how its used, and where it gets stuck. Very nice. Saying the alternative has problems isn't a great sales pitch for using that alternative. It just leaves people wondering what they should use.
Loving your videos. I've been teaching myself code for a couple of years (while directly deploying my code to prod) and have been trying to get a better grasp as to what the concepts really mean. In a practical sense. You do really well at articulating these concepts in an easy-to-understand way. Can't wait for more.
I use inheritance a lot when coding guis from scratch. All elements will share some basic functionality (such as having a position on screen, an area, the ability to draw itself, and so on) and as you develop and refine those capabilities, you want your coding to flow down to all the more specialized elements that do the same thing. When you add the ability for the element to recognize that the mouse has hovered over it for long enough to bring up popup boxes, for example, you want every element type you have to learn this ability, so you'd program it into the parent class. I can't even imagine how I'd do this cleanly and quickly without using inheritance.
"I can't even imagine how I'd do this cleanly and quickly without using inheritance" this is actually one of the problems behind OOP - "to a man with a hammer, everything looks like a nail" : ) Decorator, Strategy, Visitor...? this problem has multiple solutions and battle-tested techniques.
Without inheritance you have a class that consumes a "Position", "Area" and "Drawable" object that does so. Instead of inheriting from a class that has all three behaviours in it interleaved. Actually that is what you call complexity. Otherwise if you want to learn another approach to UI look and learn "Elm".
I’m glad to see a youtuber actually take advice from a comment, and implement it into their new videos. The highlighting is much better than the blurring
Four videos and this is already my favorite programming channel. To the point, easy to understand, fair and unbiased analysis, content this good just doesn't exist. And of course, the response to community feedback. You've done a brilliant job of taking feedback on board and responding to it, literally every complaint I've seen in the comments of your previous videos has been addressed and corrected well in this one. There's one thing I'm gonna be "that guy" about though, I'm on a 13" laptop screen, and the class diagrams are a bit difficult to read due to their size, maybe would be worth bumping it up a pt or two? And just as a maybe, at 8:42 you have bracket pairs colorized, it may be useful to have this present throughout the code samples in the video? For those of use interested in looking at the specifics of the code it would make things more readable. Maybe dip the saturation on the colors a bit though if you can, just so it fits more neatly with the editor theme and with the color scheme of the video.
@@griglog I think if the bracket colors were changed to fit in with the code color theme it would be a lot nicer, maybe just desaturated colors so they appear white but when you're looking for it you can see the color. I think there's a balance between "just make it white" and "colorize bracket pairs" which can work well for everyone.
@@alexwtf80 you mean like all the devs who are ditching OOP-first languages in favor of functional ones for the drastic improvements in productivity and efficiency? Inheritance should be used sparingly when available, and it's trivial if not easier to do pretty much everything without using inheritance. I think you're confusing now for the 90s.
I was about to write a comment how what you said in the first minute of the video, the purpose of inheritance (and also composition to an extent) being to reuse code was a gross oversimplification which completely leaves out polymorphism, one of the main benefits of inheritance. And also how the example would have been solved a lot better by the use of interfaces. Then I decided to first watch the video to the end, and it turns out you mention all those points. Very good video.
I'm sure this channel will grow exponentially in a few months. I'm happy to be here since the beginning. You are doing an amazing job both in content and visually. Thanks for sharing with us.
Love how the youtube algorithm promotes new fresh channels! I've been watching you since the first video you made and I'm glad you've picked out your niche in this oversaturated field with clear and concrete explanations. You're awesome!!!!!!!!!
At 3:27 the the red class should have a line straight to the green class, I think.. But thanks so much, the way you visualise these concepts is amazing!
These videos have been awesome and easy to digest. Please keep it up! I love that you have a pros and cons in all of them as well. Nothing is ever the only answer so breaking this down for people repeatedly is good. I once worked with a guy that was in school part time and anytime he would learn something new, that new thing was the best thing evarrrr and he would start implementing it in code at work without better consideration.
One of my favorite examples on this topic: Imagine you have a "Person" class, which implements some generic person behaviour. Then you have a "Male" and "Female" class, which both inherit from Person and implement sex specific behaviour. You also have a "Customer" and "Employee" class which also both inherit from Person and implement role specific behaviour. Now the Problem is that you cannot have any of the permutations (MaleCustomer, FemaleCustomer, MaleEmployee, FemaleEmployee) at the same time since its impossible to do this with single-class inheritance. This comes up quite a lot in many forms and is one of the primary reasons why Composition is often preferred over Inheritance.
@@ShaizRevenge This way you're doing double unnecessary coupling just to get around composition. Rather than considering the MaleCustomer as a single entity (e.g. "a male customer"), it's better to consider it as a intersection of two entities (Male & Customer, "a male that is also a customer"). This way you can also more easily represent unions, such as (Male | Customer, "either a male or a customer"). It gets even more powerful when you can also combine it with intersection (Male | Customer | (Male & Customer), "either a male, customer or a male that is also a customer"). Composition makes this incredibly easy, without the drawback of coupling everything together.
@@dealloc How you would implement those union and intersection examples without language support for unions/discriminated unions? All I can think of is having a function that takes e.g. a nullable MalenessComponent and a nullable CustomerComponent, checks if one of them is null, and then does something different in each case. But that doesn’t seem like good practice
@@orangeguy5374 Not sure how to ideally represent in languages like Java which lacks algebraic types. But from what I've found you can represent it in two ways: On a data level, you could a EnumSet or other way to define all your types of data with a corresponding flag and use its methods to check for intersection/union. Of course this is not ideal, as it would be preferred to have built-in language support. I also think there are ways to represent intersection types as least with generics, interfaces and constraints. But I am not a Java developer, so I can't speak of how that would be done on a type-level. I wouldn't overthink it though, because it can quickly result in unnecessary abstractions that makes it all more cumbersome to work with and maintain.
@@dealloc Actually, I would argue that Java is now a language with almost full support for algebraic types, ever since the addition of sealed classes and records. Funnily enough as Java is seen as the hardcore OOP language with little functional support. Anyway, my question was more about how the idea of composition over inheritance ties into all this. How does composition help you implement algebraic types?
I’m a huge fan of your videos, and was talking with some coworkers about your “never nesting” video a couple weeks back. Turns out a lot of us had seen it independently haha. You’re getting some great traction!
Great content presentation. I am referring this channel to all present and future junior devs I'm working with. Bang-on about premature optimization and the link to inheritance. The common distinction between a choice of inheritance over composition is the "Is-A" vs. "Has-A" distinction. Inheritance leans towards situations where one thing can be directly and completely represented by a base. The classic dog or cat is-an Animal. Unfortunately these decisions tend to get skewed when your perception starts looking for these optimizations early. It becomes a hammer looking at everything as a nail. I've seen scary situations where things like customers, users, and offices extend a base address type just because they all share an address. This should be a "has-a" relationship, where those classes all "have" an address, Composition. Composition is generally easier and safer to optimize for as you go. Inheritance is an optimization I prefer to encourage as a later re-factoring once the "what" everything should be has had a bit of time to settle. +1 on the grins hearing Pee-En-Gee referred to as "ping" :)
In a class I just finished, our final project was a 2D arcade game. The class was “Object Oriented programming”, and we used c++. We ran into this problem as we wanted to add features to our characters. We refactored to an Entity/component based system and it was such a relief. Minimal inheritance, mostly aggregation. Inheritance feels like OOP just trying too hard.
suddenly everyone hates inheritance like it’s some guy who shit in their cereal. Can’t we just recognize the best tools for the job and not demonize anything ? Sometimes I wonder...
@@turolretar I think the reason for that is that many people use inheritance incorrectly, or use it in situations where it shouldn't be used. Just like OOP is often hated. I've seen people hating on OOP and Java and when asked to see their code, they reveal one massive god class with all members public. Of course OOP is bad when done wrong. But to be fair to people hating OOP: in my experience, many books and tutorials on OOP aren't very good at teaching the core principles.
@@turolretar That's the thing with people -- they like and dislike what they're told to like and dislike. As a JS dev, I'm so tired of people praising such and such framework because they heard someone else say it's the best.
@@turolretar The problem with inheritance is that it tries to do code sharing and polymorphism at the same time. There are already great tools that take care of those problems individually - and better. Want to share code between classes? Use composition! Want polymorphism? Use interfaces! Want both? Use both! I've barely seen any real-world scenario where inheritance is the best option. You're adding a hard-wired dependency to your class for no reason. I find it's easy to paint yourself in a corner when relying on inheritance.
this content is like a polished gem. whenever I get recommends like this.. It feels like I have found a Lush Cave. waiting for the Dependency injection video
Love this channel! This is the exact visual representation and walk through of concepts that all books and articles lack. When are you coming out with that dependency injection video you teased about? Really looking forward to it!
This is how programming tutorials should be done. I have never seen anything better in regard to clarity, visuals or consistency. I only wish there was hundred more videos to watch. =D
I've seen class/inheritance coding before in large projects, such as BioPerl. File reading/writing are their own classes. Data storage are another set of classes. Each uses some amount of inheritance to work. For example reading/writing a FASTA file vs a CSV vs Etc... all have a base class to work from and the data held being a Seq, RichSeq, etc... also have their own base class to work from. What you did in the video mixing reading/writing with the holding/manipulating is what creates the real problems when trying to use classes and inheritance :)
Holy crap this channel is liquid gold. I'm entirely self taught and have always been a little in the dark when it came to proper abstraction and inheritance. This clears it up soo much! Can't wait for the next upload.
Interestingly enough, just yesterday I was trying to formulate in my head when I would use inheritance vs composition, and the answer I came up seems to be in line with your video: Use inheritance for designing well defined interfaces, and composition for just about anything else. Thank you for making this video. I intend to show it to some of my newer-in-industry coworkers.
It's worth pointing out that there are a great many different applications of programming, and not all of them lend themselves well to every paradigm. Generally speaking, I think Object Oriented Programming, and inheritance, are very powerful when writing or consuming a library with a public-facing API. The ability to create a set of classes which can be inherited from, and the ability to extend the classes in an API, are quite valuable. But most application code tends to benefit more from a functional or procedural design.
A good approach is to use interfaces first, that way you declare what is necessary. Then if you really need inheritance, you can make an abstract parent class that inherits from the interface and contains the boiler plate code you want. This way, not everything that implements the interface also has to inherit all the functionality as well. That can stay restricted only to subclasses where it is actually helpful. Still it is better to avoid this most of the time. Interfaces are fantastic though
One of the better cases for using inheritance is to provide extension points to override behaviour in a class. Using the image example from the video, a TIFF class may provide an extension point to allow additional meta data to be written into the class. Similarly, the PNG and JPG classes may be subsclassed with WaterMarkedPNG and WatermarkedJPG classes....where all behaviour is the same, except when streaming the image. You could do this with composition, but it is far easier with inheritance.
@@jimiscott Yes, easier to implement initially with inheritance, due to less boilerplate. But you trade off flexibility. Consider that some requirements change for the parent classes, but should not change for the subclasses, then you now have an incompatibility, and in an ideal world you would decouple them. But time is money, so you end up patching it by overriding all subclasses to ignore this requirement, or over-abstract the entire thing, ending up with more debt. We have to consider what would happen in the real world, rather than what is theoretically possible, if we had infinite time to do things. Of course it could be considered on a case-by-case basis. But sticking with composition will make things much more easily manoeuvrable, even you tradeoff by having to write extra boilerplate.
Thank you for this. Due to the types of projects I code, I'm constantly struggling with the inheritance refactoring woes you speak of. I have a serious case of imposter syndrome though, and just assumed I was doing it wrong. I've since switched to using the composition method you went over, but wasn't very strong in its fundamentals...and assumed I was doing IT wrong as well (which in some cases, I was). Laying them out like this is exactly what I needed, and you saved me hours of trial and error due to a combination of incorrect assumptions and a lack of a strong foundation. Seriously, thank you.
It would be so great to also mention more technical terms for this, like the Dependency Inversion Principle (related to using interfaces), Strategy pattern, etc.. Yeah, you gave a brief explanation of why it is useful, but just throw another bone to the devs who want to find out more about the topic more easily.
I wrote an image class just as an exercise about 25 years ago. It was the best lesson on the limitations of inheritance (and templates) I could have ever wished for.
Yep dependency injection and interfaces are a great solution. But it's worth noting that more strategies exist. C# has also extension methods, which are basically static methods, but used with a notation of actual methods. And the Rust language has a very interesting typing system which is based on so called traits, really worth to learn about. But if I choose to use inheritance, I will do it only in the same project for a small set of classes, but not for public library code. And only just a single base class, expecially no deep interitance trees. Keep it simple. Last note, methods in C# are sealed by default (you cannot even use that keyword). This differs from Java. But you can make your classes sealed as well, but which is not by default by the language and which is a very good practice to do by yourself.
As someone who has been trying to understand what inheritance was in the first place for a while, or why it would be used, this video helped me greatly! and THEN you beautifully describe what composition is as well!
As with most examples of problems with inheritance/OOP, I feel that the example used here and the particular way that it breaks down is more of a design problem, less of an OOP problem. The three format dependent classes really don't make much sense as subclasses in the first place - why do I care about JpegImage if the only JPEG specific part is how it loads and saves the file? In memory, all the images are the same, so there isn't really a reason for them to not all just be Image. The compositional approach works here, but I would go another direction. Create an ImageFileHandler class, and give it methods for each type of image. Give the Image class an imageFileHandler, have its save/load methods delegate to this. Technically any image could be saved to any format, so we should go ahead and add a parameter to save to specify the format, and/or include a property the remembers the original format. But for loading, why not just detect the format by file extension. Now we have an Image class that can load/save images in any format without the user even needing to think about it. New formats can be supported by updating ImageFileHandler and Image doesn't even need to know what the format was! Alternatively, instead of embedding the file handler inside the Image, a new ImageLoader class could be created, and it would be an Image factory - the load method would return a new Image, and the save method would take an image as an argument.
UA-cam recommended this video to me again with no indication that I had already seen it. And I was thinking exactly the same thing I was thinking almost a year ago, scrolled down to comment, only to see that I already had. Very strange feeling.
can you believe this guy only has 4 videos on his channel , wow, we need more man, more. Also code snippets of videos, would help me and am sure any see those differences and appreciate your content better. thanks man.
Loving the growth of the channel! Keep making these videos! One note, sometimes it can be hard to tell which lines of code you are referring to when the screen is full of code. Play with ways to focus attention where you want it to be. I found myself having to watch a few segments multiple times to notice everything you were doing onscreen.
I have been really confused by how to implement Interfaces basically since I started learning about them. Thank you for explaining this in a way I can finally understand!
Inheratance was incredibly useful for me once. The most interesting comment I have heard about it went something like: "My the time you understand enough about the problem to use inheritance, you have already coded the entire thing" And that is my experience. It is hard to use because it requies a more complete understanding of the problem than we have most of the time, and we don't use it very often, and it is the sorto of technique that even in programming class you will never be given an example of when it is actually useful, instead you will be given a few hypothetically situations where using it is possible but quadruples the amount of work to solve the problem. Inheritance is the perfect way to solve quite a few problems, but it is not practical 99% of the time.
Very good points. You have to constantly be going back to see what the parent does only to find out that it's that parent's parent that implements something. You have to maintain an awful lot of crap in your head at once.
No. Simply put, inheritance is a powerful tool that needs experience to be used properly. The design described in the video is deeply flawed, it's an antipattern and I would scold if any of my guys do something like that.
I wish I had a channel like this to look to when I was trying to step up my game from a programmer who just knew how programming worked to a programmer who knows how to write code the right way. Despite being a professional for quite some time, this still really solidified a lot of things that I've already learned myself and makes me feel a lot more confident about the design ideas I've already made (and maybe question some of the ones I've made in the past). A++ recommendation for anyone trying to get out of the shackles of being an intermediate programmer.
A very nice channel and the comment section is worth reading to. I think one of the things helping with this is that design is often a balance , and your videos acknowledge this. Humans can often get “religious” or “political“ by thinking there is one right answer, but this really shuts down your thoughts and the conversation. Good job.
One additional factor that makes composition preferable to inheritance is in cases where an inheritance tree grows deeper and more complex and you want to share code between two branches that are otherwise unrelated. You may be able to deal with most of those issues with more inheritance, but they will be incredibly convoluted and confusing. In some cases it may be impossible to achieve.
also if you need to change the hierarchy one day (because one of the traits modelled through inheritance will be removed, and some other one will be added). inheritance hierarchies are notoriously unflexible, so such refactoring will create a powerful domino/ripple effect throughout a codeabse (if it relied on inheritance a lot). with composition this impact is limited to a minimum.
Composition can grow unmanageable too, if done wrong. Any tool can be abused, but that doesn't make them inherently bad. Try to use a knife as a screwdriver, and it will kind of work, but not well. Try to use a screwdriver to slice bread, and it will perform horribly. I found that you can't just follow exact rules blindly, programming is too complex for that. The best you can do is having core principles that are vague and contradicting each other. That's why programming hasn't been automated yet.
@@andrasbiro3007 sure. But, in my experience, inheritance is the tool that gets abused the most and most often. And abuse of composition can make code difficult to read and understand. Abuse of inheritance can make certain changes or improvements impossible without what constitutes a complete overhaul.
@@Vendavalez Difficult to read also means very hard to change. Don't blame the tool, blame the user. I've been using inheritance extensively for like 35 years, and never ran into big issues. I refactor the offending code long before it can cause big problems.
@@andrasbiro3007 two questions for you. Are you the only person working with your code base? If the answer is no, now many of those people are juniors?
I never understood the purposes of inheritance and interfaces and why you would use them at all. This did a better job at making me understand it than my university did.
@ghost mall like Fireship as in high video production explainers for dev stuff. Both channels produce good content but serve different needs/functions.
I see that you switched from blurring out the unfocussed portions of the code (as it was in your previous videos) to darken them, as to emphasise the relevant lines that you are discussing. This makes it so much easier to follow your explanations. Thank you for being open minded and listening to your audience's suggestions. Great video, as always.
This is perfect, I'm loving the Oriented Object Programming series. Are you planning running through other topics like Data Oriented Design or Functional programming?
I saw all your 4 videos today, and I'm sure I will keep watching your content. +1 sub for you! I haven't seen any info about who you are or where your experience come from, but to me, it looks like you're learning much by yourself, because as far as I know as a self-taught dev, you don't tell people to code the way people learn in school, you tell people to write code that actually makes it easier for everyone to read and understand the code, even for non-devs I'm used to teach people, help people and learn how to improve my code, and with that experience, content like this makes it so much easier to explain to other people why I write code the way I do, because you literally explain in depth the reason for why my coding style can be so good, which I'm 100% sure is your coding style as well :P
Abstract classes and interfaces are not mutually exclusive. I would claim that the two serve completely different purposes. Often I define an interface for the bare conceivable minimum for a certain entity, then have an abstract class implement most of the interface and finally having a couple of specific final classes for the current known implementations. This pattern has yet to come back and bite me. I would never refer to the abstract class directly as an argument, property or similar. I only use it as a path to reuse code.
Dude this was the video I needed. Have been working on a new code base at work and the architect has introduced an absurd amount of inheritance. I've really struggled working on it and this video has given me the counterpoints / system design ideas to push back a little stronger. Thankyou!
I've been wanting to learn how you animate your code. Or mainly, how you get highlighted code like this that's also easy to animate. I know my way around DaVinci Resolve's Fusion but that seems like an imperfect solution for this. Could you shortly elaborate how you achieve your animation? That would be a great help in my learning efforts and might get me back into making some programming videos again :). Thanks a lot and please keep on delivering such quality content.
Great video. I like that you exposed and solve the problem with the same code base. Most of the time a complex problem is exposed but the author is switching to a different codebase to expose a solution.
Good composition is preferable to bad inheritance, but good inheritance is preferable to good composition. If you're defining your inheritance properly it shouldn't have the drawbacks you stated. But, like anything, it can be done wrong. I hate coming into a codebase and seeing things like "ImageDraw" because that's only part of an object. It's not a thing, and it's not clear what it's modeling, or what it does. If you model your image class hierarchy correctly, they should be intuitive to understand, which you lose with composition.
Bro.. I dedicated my life to learning and dev since I was 8, and I gotta say you’ve got such a finessed approach that is easy to digest and retain simultaneously. Well done, my friend, well freaking done!🎉
@@jbritain According to en.wikipedia.org/wiki/Portable_Network_Graphics you're wrong, and actually even according to libpng and w3c (source 2 and 3 in the footnotes on that Wikipedia page) you are also wrong. If you're gonna be assertive, at least be correct.
@@eckligt I mean the creator of the gif format pronounces his own format incorrectly 😉 The "official pronunciation" of PNG honestly looks like a nod to the intended/proposed name "PING" to be a recursive acronym to mean "PING is not GIF", though that's only recursive if the name remained as "PING", which it didn't; it ended up being named "PNG" which SHOULD come with its own pronunciation. I imagine it stuck since without a vowel to make it feel like a "word" like JPEG or GIF they wanted a way for people to say it quickly and easily but in a world where people just read "png" on their screens we see that's not the case. Language is supposed to evolve, and that evolution often follows the colloquial path.
It’s strange talking about composition without dependency injection. My understanding of composition is that objects are ‘composed’ of other objects/interfaces. This allows for more straightforward initialization, maintenance, testing and extensibility (among other things) Your first example of composition, a common class was passed to the signature of a method of three independent classes, which to my understanding, isn’t composition (correct me if I’m wrong) It almost seemed a bit backwards where if you wanted a compositionally alternative to your inheritance example, you’d have an image class with with an image processor interface in it. From there you’d have an image processor for jpg, bitmap, etc… (not saying I like this way better than your way) But your second example of composition with interfaces aligns better with my understanding. Again, correct me if I’m wrong. I could be too dependency injection brained and can’t remember alternative ways to build compositionally
I think the example of inheritance was weakly designed on purpose, in order to refactor it cleanly; the initial concrete class has too many responsibilities. The first example of composition @4:33 may be a bit misleading : there is NO composition between JpgImage and Image because their lifetimes are unrelated. In a true composition, one class have the responsibility to destroy the other when it's destroyed itself. Here it's a simple Dependency, JpgImage uses Image, but Image is not a structural part of ImageJpg or vice versa so it's not an Aggregation. In the second example of "composition" @4:50, there IS an Aggregation between ImageDraw and Image, ImageDraw has an Image as a part of its structure. However there is no indication about their respective lifetimes. So we should not say it's a Composition as per the UML definition, but it's close enough for the purpose of the video. Even if we push an Image in the constructor of ImageDraw, it is NOT dependency injection. The purpose of dependency injection is not to build a composite object, it is to inject an interface (instead of a concrete class) into another class in order to cut the dependencies over a specific implementation, and to facilitate testing (using mocks instead of an actual database, a physical file, or a webservice for example); nice example of DI @8:01
Usually composition refers to an entity having an array of components which makes the entity agnostic to its own properties. Only external systems would be able to work on each individual component of the entity, hence we have composition since you can define a male/female as components of the composition and have them accessed only by the "sex" behavior systems
This is not what I'm thinking of when I hear composition either, to my ears this sounds more like the kind of service-oriented programming that is popular today (for good reason - it's good). Composition as I recall it tends to suffer from the fact that the composed class may need to restate all the desired methods, with the body of the restated method simply calling the method on the property which implements the desired functionality. Even the wikipedia article on on this ( en.wikipedia.org/wiki/Composition_over_inheritance ) states: "Composition over inheritance (or composite reuse principle) in object-oriented programming (OOP) is the principle that classes should achieve polymorphic behavior and code reuse by their composition (by containing instances of other classes that implement the desired functionality) rather than inheritance from a base or parent class."
In all my years of professional programming I've used Composition over Inheritance like 95% of the time but never really thought about much of it. Thanks for giving me something to think about and love the channel man; keep up the good work.
You still inherit base class for BmpImage in 4:44. Also I think t's kind of weird "in between" way to implement this - holding path as property while passing Image by reference, and mutating Image during load. I would personally either make these classes completely stateless ( void save(Image image, string path), Image load(string path) ), or also hold ownership of Image as class member. Nevertheless, concept by itself is exceptionally explained - great job!
They're not bad, it's just the common trap many devs fall into when it comes to "WORKS AT SCALE". Relational DBs can be scaled and run as nodes just like NoSQL DBs. The thing that truly puzzles me is that some popular NoSQL DBs have terrible transaction handling which should make devs terrified of using them in production, but people don't think of that.
Interfaces have the potential to recreate the same problem that inheritance causes. It makes your code less maintainable. If an interface is ever changed, then all classes that implement it must be changed as well. Using interfaces to allow for polymorphism in your compositions can potentially create just as many problems as inheritance. Both can allow for maintainable code if implemented correctly. In your images example, inheritance wasn't done correctly and that is why there is a problem with the save/load functions. The designers of the image class should have acknowledged that there should have been another class between those in the inheritance tree. Their design assumes that all images are "savable." A SavableImage class should be between the Image class and the children. Or, in my opinion, a savable interface should be implemented because savable things are not always images and therefore other classes could also implement those methods. I feel like most of the problems people have with inheritance is because there simply isn't enough layers in the inheritance tree to describe the changes between parents and children. If careful thought is put into the maintainability of the code at the time of design, a lot of issues like this particular one can be avoided. Not saying that inheritance is infallible if done correctly, it definitely can be used incorrectly. I just think too many people avoid the concept because that's the latest fad, and the real issue is that people need to spend more time on designing their ideas instead of just coding them.
Good points! I think one of the main reason for people misusing inheritance is the damaging rule-of-thumb I've encountered so many times, that inheritance shouldn't be more than one level deep below the base class. If followed strictly, one ends up with the problem you describe. I agree that the example in the video has an excellent example of having Saveable as an interface and an Image as a base class which knows nothing about saving and loading itself. It shouldn't be the responsibility of the image to know how to save itself.
Best explanation of object composition vs inheritance I have seen so far, great example makes it easy to understand the conceptual differences and pros and cons here. Thanks for a nice video covering this!
One thing that puts me on "inheritance always sucks" side is many times you'll have multiple shared behaviors which don't align with any hierarchical structure. A child class cannot inherit from multiple parents, but it can inherit from multiple interfaces (typeclasses, traits, etc.). A quick example: Let's say you have three classes: Bike, Car, Helicopter. Bikes and Cars have wheels, and Helicopters and Cars have baggage holds. You want to write methods that handle baggage holds (put stuff in and out) and wheels (rotate them, count them, etc.). It is impossible to create appropriate parent classes for this purpose - you would have to have a parent class for Bikes and Cars to inherit from, and one for Helicopters and Cars to inherit from, which is impossible with classes (because Car inherits twice) but not interfaces. You can't make a parent class that encompasses all those behaviors either, because then it would have to have useless functions for some of those subclasses and throw errors/panic/etc. when you call them. Because this structure is not hierarchical, where bigger concept contains smaller concepts, but instead you have concepts that overlap for some thing and don't for others and structure is disjoint, inheritance is completely inadequate to handle this scenario, even though it's fairly simple. If we'd learned anything from database programming, most things are linked chaotically and not at all in a hierarchical structure. Your data structures can share traits with many other data structures that don't contain it or aren't contained within it. This is why I like that Rust has no inheritance for structs - if you want shared behavior, use traits to describe it. This allows Rust to describe shared behavior even for built-in types, where a lot of them are composed of various combinations of traits.
I feel like, in this instance, it would probably be best to make a Wheel class and a BaggageHold class, then make those members of the Bike, Car, and Helicopter classes, accessible with car.wheels or helicopter.baggageHold. However, some languages have multiple inheritance or mixins which could also be used to solve the problem
@@tomysshadow Sure, but that's composition. And imagine you can't do that, let's say you have wheels and axels. Both rotate, so you have to make a stupid class RotatingThing, that defines a method rotate(). But wait, that's basically an interface
I love the change from blurred code to highlighted and dimmed code. I found this much more legible and easier to follow. Please don't burn out on these. I think you're filling a niche that is poorly served elsewhere, I hope you've got a long future here.
I was a little concerned you wouldn't mention any of the cons of composition at all, but you eventually did, although its likely late enough in the video where a lot of people wouldn't have seen it. Particularly with large scale projects, inheritance becomes much more important, as you alluded to in your pros and cons list.
I love the 'real world' examples. Usually I'd see examples like an Animal class or Foo and Bar but these examples make it 'click' easier in my head.
Not a fan of foo and bar. To a beginner, they look like some obscure function or keyword. Animals are a much better subject in this regard. Also don't like "my" classes, something just doesn't sit right with me about them.
@@2bfrank657 I agree the "my" classes aren't very descriptive but one thing i do like about those examples is that they imply they are an identifier, meaning it is named by the programmer rather than being a keyword. Not too useful for any topic outside of the basics, however.
Yeah the problem with those examples they use is that it's only useful to people with the lowest level of understanding. And that level is certainly not where most programmers struggle.
Also the problem you try to solve is to break down complexity. Not just to understand the mechanisms, but why these mechanisms are the best approach. With 'animal' examples you don't hit that type of complexity. And specifically: The biological tree of life does not have the same properties as a good class hierarchy. And prevents good understanding.
Same here. 9/10 articles they make these bare bone, unrealistic examples and call it a day, and I have a hard time then translating it to real world situations.
It's truly unbelievable, in 30 days with 4 videos, 100K subscribers. I have never seen anything like this before. Excellent work, keep going with these small but crucial programming details.
beluga
You have not seen much.
my mans just making equisite videos for a niche audience innit, love of the game my darling
@@henryjobling9178 I did not understand what you said, why?
High-quality, good niche
First time I've heard PNG called "ping", hits different
It's the official pronunciation. I don't think I've heard the letters spelled out.
@@eckligt TIL. On Wikipedia, it shows the separate letter pronunciation. Oxford dictionary also shows the individual letters. Everyone I know says the letters individually lol
@@eckligt the opposite is true for me
I've always known it as png since I was a kid and first encountered it. Born in 83 for reference. Also, "gif" is pronounced like the peanut butter "jif". "gib", an old term from gaming that I shan't tell you what it means (we don't want kids changing the meaning) is pronounced with a J sound at the beginning... And that comes from the famous developer that made the word popular.
same, it sounds very strange when the letters aren't pronouced individually
This channel is quickly becoming one of my favorite programming-related channels. I'm sure I'm not the only one who appeciates the clear explanations coupled with beautiful animation - It's like 1brown3blue for programming.
It is called "3blue1brown" lol
any other recommended programming channel you have?
you are too gullible
You will be big soon, you content is just quality. Keep it up
85k subs in a month is still pr impressive though
Share the video in your social media to help it grow then, stop bragging
@@MassimoRough bragging about what?? stfu
Indeed! It's the only channel that I have activated notifications for.
Frfr
I've found that tight interfaces with default implementations have provided a really nice balance between minimizing common business logic and preventing tight coupling when you lean on multiple interface implementation. It allows you to mostly lean on composition (implementing the interfaces you care about) while gaining some benefits of inheritance (common methods have a default implementation to reduce code reuse)
agreed - interface -> abstract -> impl has been a winner every time we've needed to scale
I've been programming for over a decade and these videos explain things I already know or thought I knew in ways that make me question some of my own designs over the years! Thank you very much! I always feel like I come away from your videos with something useful to think about.
As I learn more, I always scold myself for things I've built in the past.
EIther I am too demanding on, and/or too expecting from my subordinates to improve themselves and know all of this, or you lack a lot of knowledge, if you do not design code like in the "good" examples in this video automatically after over a decade of programming. Everybody on my team, even people with less than 3 years of experience, is taught technical architecture through conventions and prepared documentation.
@@Ondraasha What is the point of slamming some random dude praising the video? Also, why do you write 50-word sentences?
Either I am too demanding on, and/or too expecting from my subordinates to improve themselves and know all of this, or you lack a lot of knowledge, if you do not design sentences like me in the "good" previous two sentences I made in this comment automatically after over two or three decades of speaking English. Everybody on my team, even people with less than 3 years of experience, is taught technical sentence structure through conventions and prepared documentation.
Java really popularized inheritance based programming, and it WAS the go-to paradigm for a long time. Only recently has most of us come to terms with its inherent issues. I don't blame people for using inheritance, I've done it myself a lot. The past is the past. Instead we should focus on the future. We will never stop learning and improving unless we give up, and we need to come to terms with that reality that what we did before likely _IS_ flawed.
@@MrMudbill Yes, Java, PHP, and Javascript are the real offenders here teaching hundreds of thousands of developers to stick with OOP Inheritance. Learning and writing Rust, Go, Lisp, and many other languages helps expose people to better ideas.
This is by far the best explanation of the topic I’ve ever seen. Not overly complicated, but what’s even more impressive - not unnecessarily dumbed down as well. Fantastic content.
Bro you are a blessing. Your ability to convey the message without extra speech is a gift. Its like every word you say is useful. Thank you 🙏
There is a risk of conflating fine-made delivery with a correct content. Price is paid by ones who fallen under this fallacy.
In game development the most common composition pattern is called an Entity Component System (ECS). You pay a small price in object creation & destruction, but you gain optimal memory access and incredible flexibility!
It’s not immediately applicable to other disciplines of programming, but I’d still highly recommend it to everyone. It’s like the game development version of dependency injection.
Also, virtual function tables are pretty fast in C++
Unity has a Component model and a ECS model, Unreal uses an Actor model
ECS has gained popularity later, and is not a magic silver bullet.
Game Dev is still a heavy OO world (opposed to ECS, which is data driven) where a lot of Inheritance is used along with composition
@@neonbyte1337it's not about whether vtables are fast or not, one of the main benefits of ECS is that components are sequential in memory, meaning you heavily reduce cache misses and keep your cache full of the data you're going to be processing. It's excellent for quickly and effectively processing lots of elements, and having your data layed out as POD and also sequentially makes multi threading much more convenient to manage.
This is quickly becoming a top favourite coding channel of mine. The topics are explained wonderfully and I love the visual style. Each of these videos are so easy on the eye, easy to follow, and quick to understand. I think it's because you're to-the-point, you're demonstrating what you're talking about, as you're talking about it; and you demonstrate the importance or usefulness of what you're trying to teach, all in a way that looks beautiful. I look forward to more, they're a joy to watch.
Can you suggest other coding channels?
my first time here. reminds of 3 blue 1 brown quite strongly. (not a bad thing!).
@@eliezra83771 Sure! I recommend Amigoscode, Bro Code, Chris Hawkes, Chris Titus Tech, Code Creative, Codinghase, Computerphile (for Computer Science topics), Continuous Delivery (for Software Engineering topics), DevDuck, Fireship, ForrestKnight, freeCodeCamp, GOTO Conferences (for various talks), Hallden, Keep on Coding, LiveCoder, Mansoor Codes, Missing Semester (very useful!), and NeetCode.
You have no idea how long i search for content like yours, as a self taught coder, i had been watching many programming language tutorial explaining about what is variable, for, while, do while, if statement boolean and many others basic programming concept. but ALL of them never bothered explaining the next crucial step between the basic and advance which is how to design your code structure.
everyone can write code that a compiler can understand and compiled so the program can run... but not many people can write code that does what i said before AND design the structure of the code CORRECTLY. in fact, i had never see any website or UA-cam programming tutorial taught how to design the structure of the code in the most efficient manner... it seems that you have found yourself a niche in Programming Tutorial UA-cam Channel. and for that sir, you deserve a subscription.
The brief animation at 5:44 does such a great job explaining the value of abstracting the contract of relationships between code!
This guy deserves the best.
Many people teach beginners how to code, but only masters teach experienced how to code correctly.
I would love to see a channel like this explain to the broader community the concepts of SOLID and other principles. So wide is the gap between bad and decent code, and simple strategies to mitigate code smell and technical debt would do many wonders!
May I recommend ArjanCodes? He did just that.
@@3_smh_3 Single Responsibility make code both easier to read and easier to maintain. It reduces decoupling and reduces the opportunity of code smell. By that alone, code can be objectively better.
Open close principle allows for code to be maintained through less need to couple code. Thus, any change to project requirements requires less code refactoring.
Liskov subscription is literally "good adhoc polymorphism". It allows you to do things such as dependency injection.
Interface segregation means clients do not need to require more than the required interface, as seen in this video (though, composition can be better)
Dependency inversion is similar to injection. Except, it is the principle upon relying on the abstraction rather than just moving code to somewhere else.
This is all to say that I VERY much disagree that it is bad to know and employ. It should be second language to a dev, and employed to the appropriate degree in a project.
The problem is that the difference between good and bad code is big and small at the same time.
Big because you need to know how to do it and why, small because you will be typing the same or even less code to get the the results you want.
@@PereViader Code smell is a vast topic indeed, but design principles were coined and employed for a reason. Much like how design patterns were developed to solve common problems. The help reduce the several kinds of code smell and maintain better code.
Edit: oop I misread your words
@@3_smh_3 That's fine. I mean, they're just a collection of best-practices, really. I feal that SRP in SOLID is the most common and enforced, since it follows from basic code habits, such as self-documenting code.
I'm a firm believer of "Best tool for the Job". I use Inheritance, Dependency Injection, and Interface Composition intermixed in the same code base. It is important to understand that each of these things are just tools that each have pros and cons, and they can all easily cohabitate in the same code base. Saying "don't use inheritance" is an inappropriate hardline, and inheritance has very strong uses. There's also Default Implementation for interfaces that has been introduced in a lot of modern languages over the last few years which has been excellent. It provides a way to leverage interfaces as a way to perform composition without having to do direct inheritance.
Only good reply here. Making DrawableImage inherit Image was just wrong inheritance use.
@@atlantic_love What are you talking about? Learning to use the best tool for the job is like the lesson at the core of software engineering. It is beyond "Useful"
@@atlantic_love Are "Inheritance", "Composition" and "Dependency Injection" the big words? If so, they are "Design Patterns"!. They are a way to structure code following some rules which are supposed to make larg codebases more mantainable and easy to scale, you can learn a lot about them online, and they are used all the time! The names might be complicated, but they are very easy to demistify. Refactoring Guru is a great free resource for example
The OP is making a comment about a general rule: "Composition Over Inheritance" associated with these design patterns (Originally coming from the flus Gang of Four book). And saying how this is commonly repeated outside of this context. Making new programers think inheritance is bad. While, in reality, inheritance is just a tool. And while it might not be the best tool for every job. There are a lot of jobs for which it IS the best tool. Having this knowledge in mind is, in my opinion, VERY useful. Specially for programers new to OOP
@@atlantic_love If you were unable to understand what I am saying, that's completely ok as a novice programmer. I did use a few technical terms, which if you stick with a career in programming you'll come to learn. But it's not nice to say that because I used technical terms in a comment to a technical video that I'm "not saying anything useful". I have a made contradictory argument against his hard-line "Don't use inheritance" stance. If you don't agree with my point of view, that's fine and feel free to express your own opinion on the matter.
@@atlantic_love you either did not watch this video, or did not understand the point they were making. The video makes the argument that inheritance should be entirely avoided due to its flaws. My counter argument is that Inheritance should not be avoided but rather embraced when it makes sense, hence the "best tool for the job". If you're not going to provide any helpful insights or opinions to the conversation, then this entire issue you have with my original comment is moot.
This channel never disappoints
how do you know? It's a 10 minutes video and you posted your comment after only 2 minutes since the video was posted
@@i_dont_likevodka3062 they skip n watch in x2 speeed
@@i_dont_likevodka3062 they are talking about the videos this guy uploaded in the past probably
i mean more the topics, I was wondering this the other day and then this pops up in my feed!
This channel don't miss!!!!
So there are concepts that are either:
1. I understand them well enough already I don't feel especially compelled to continue researching them
or 2. I know they're a gap for me, but I've tried to understand them too much without real payoff, and I've just given up on pursuing those topics.
This channel consistently advances my knowledge in both categories. This video would be an example of the 2nd. Really fantastic work here.
as an artist turn recent programmer I gotta say THANKS. These are so concise, make sense even to me, and are coming at a great time.
This video is great. And it makes me thingk how real world problems are what really make you learn. If you learn this composition like in university lectures, they'll use examples like Animal, Foo, Toto... you may understand maybe on those examples but you'll never get it at 100% and this video is the proof. Getting involved is the best way to learn stuff, directly to the real parts.
Amzing video btw!
I did something similar recently where I wrote a trait based rust composition pattern but realized there was a common structure across all implementing classes. I made the code more succinct by creating an "optional inheritance" with its own blanket implementations so for the 99% of implementing classes you can just inherit and get the traits for free and just implement the last trait needed for integration. What makes this optional is that you can just derive the traits that are needed for the framework (requiring implementing the otherwise blanket implementations yourself) and not inherit the "helper" parent class. That way you get the best of both worlds.
In 10 minutes you've clearly stated what it has taken several books 100's of pages to explain. Fantastic!
I don't know if you actually read my comment on your video "Abstraction Can Make Your Code Worse", but this is 1) so much better by not making the choice for the viewer, instead clearly stating your opinion and allowing them to come to their own conclusion and 2) an amazing companion video to the discussion around abstraction as a whole. I'm looking forward to the video on Dependency Injection, if for nothing else than because of the great quality of material and informational topics you've covered.
Keep growing, and I look forward to the next topic.
I love the way you showed code as you explained the concepts, how its used, and where it gets stuck. Very nice. Saying the alternative has problems isn't a great sales pitch for using that alternative. It just leaves people wondering what they should use.
It's not suppose to be a sales pitch. Both of the ways should be used correctly when needed. It's just depends on the need
Loving your videos. I've been teaching myself code for a couple of years (while directly deploying my code to prod) and have been trying to get a better grasp as to what the concepts really mean. In a practical sense. You do really well at articulating these concepts in an easy-to-understand way. Can't wait for more.
I use inheritance a lot when coding guis from scratch. All elements will share some basic functionality (such as having a position on screen, an area, the ability to draw itself, and so on) and as you develop and refine those capabilities, you want your coding to flow down to all the more specialized elements that do the same thing. When you add the ability for the element to recognize that the mouse has hovered over it for long enough to bring up popup boxes, for example, you want every element type you have to learn this ability, so you'd program it into the parent class. I can't even imagine how I'd do this cleanly and quickly without using inheritance.
"I can't even imagine how I'd do this cleanly and quickly without using inheritance"
this is actually one of the problems behind OOP - "to a man with a hammer, everything looks like a nail" : )
Decorator, Strategy, Visitor...? this problem has multiple solutions and battle-tested techniques.
Without inheritance you have a class that consumes a "Position", "Area" and "Drawable" object that does so. Instead of inheriting from a class that has all three behaviours in it interleaved. Actually that is what you call complexity. Otherwise if you want to learn another approach to UI look and learn "Elm".
This channel gives me 3blue1brown vibes and I absolutely dig it! Can't wait for more :)
Very similar aesthetic, and honestly a pretty similar voice/tone/cadence.
Maybe because of the usage of the same library (manim) for creation.
@@aksh1618 did they use the same library for the voice too?
@@wtfzalgo looool
I was thinking the same 👍
I’m glad to see a youtuber actually take advice from a comment, and implement it into their new videos. The highlighting is much better than the blurring
Four videos and this is already my favorite programming channel. To the point, easy to understand, fair and unbiased analysis, content this good just doesn't exist.
And of course, the response to community feedback. You've done a brilliant job of taking feedback on board and responding to it, literally every complaint I've seen in the comments of your previous videos has been addressed and corrected well in this one.
There's one thing I'm gonna be "that guy" about though, I'm on a 13" laptop screen, and the class diagrams are a bit difficult to read due to their size, maybe would be worth bumping it up a pt or two?
And just as a maybe, at 8:42 you have bracket pairs colorized, it may be useful to have this present throughout the code samples in the video? For those of use interested in looking at the specifics of the code it would make things more readable. Maybe dip the saturation on the colors a bit though if you can, just so it fits more neatly with the editor theme and with the color scheme of the video.
Personally I dislike the colored braces. Making 4 spaces of indentation is already perfectly readable and more colors is distractong
@@griglog I think if the bracket colors were changed to fit in with the code color theme it would be a lot nicer, maybe just desaturated colors so they appear white but when you're looking for it you can see the color.
I think there's a balance between "just make it white" and "colorize bracket pairs" which can work well for everyone.
"To the point, easy to understand, fair and unbiased analysis"
And wrong. This make any sw engineer cringe a lot.
@@alexwtf80 you mean like all the devs who are ditching OOP-first languages in favor of functional ones for the drastic improvements in productivity and efficiency?
Inheritance should be used sparingly when available, and it's trivial if not easier to do pretty much everything without using inheritance.
I think you're confusing now for the 90s.
@@willsterjohnson I have yet to see all those devs. Also, paradigms are tools, you choose the best for your problem, there isn't a universal answer.
I was about to write a comment how what you said in the first minute of the video, the purpose of inheritance (and also composition to an extent) being to reuse code was a gross oversimplification which completely leaves out polymorphism, one of the main benefits of inheritance. And also how the example would have been solved a lot better by the use of interfaces. Then I decided to first watch the video to the end, and it turns out you mention all those points. Very good video.
I'm sure this channel will grow exponentially in a few months. I'm happy to be here since the beginning. You are doing an amazing job both in content and visually. Thanks for sharing with us.
I like this professional and visual representation of whatever you are trying to explain, because its really easy to understand
It's pleasant to have these core concept explained with this much quality😌
Love how the youtube algorithm promotes new fresh channels! I've been watching you since the first video you made and I'm glad you've picked out your niche in this oversaturated field with clear and concrete explanations. You're awesome!!!!!!!!!
At 3:27 the the red class should have a line straight to the green class, I think.. But thanks so much, the way you visualise these concepts is amazing!
In this video, he uses more than one design pattern, specially when explaining abstraction by composition.
Really well explained.
These videos have been awesome and easy to digest. Please keep it up! I love that you have a pros and cons in all of them as well. Nothing is ever the only answer so breaking this down for people repeatedly is good. I once worked with a guy that was in school part time and anytime he would learn something new, that new thing was the best thing evarrrr and he would start implementing it in code at work without better consideration.
This type of videos are like a hole semester of classes in 10 minutes, thanks a lot and keep it up! please!
One of my favorite examples on this topic:
Imagine you have a "Person" class, which implements some generic person behaviour. Then you have a "Male" and "Female" class, which both inherit from Person and implement sex specific behaviour. You also have a "Customer" and "Employee" class which also both inherit from Person and implement role specific behaviour. Now the Problem is that you cannot have any of the permutations (MaleCustomer, FemaleCustomer, MaleEmployee, FemaleEmployee) at the same time since its impossible to do this with single-class inheritance.
This comes up quite a lot in many forms and is one of the primary reasons why Composition is often preferred over Inheritance.
What about languages like Python where you can inherit from multiple classes? You could make any permutation that you like.
@@ShaizRevenge This way you're doing double unnecessary coupling just to get around composition.
Rather than considering the MaleCustomer as a single entity (e.g. "a male customer"), it's better to consider it as a intersection of two entities (Male & Customer, "a male that is also a customer").
This way you can also more easily represent unions, such as (Male | Customer, "either a male or a customer"). It gets even more powerful when you can also combine it with intersection (Male | Customer | (Male & Customer), "either a male, customer or a male that is also a customer").
Composition makes this incredibly easy, without the drawback of coupling everything together.
@@dealloc
How you would implement those union and intersection examples without language support for unions/discriminated unions? All I can think of is having a function that takes e.g. a nullable MalenessComponent and a nullable CustomerComponent, checks if one of them is null, and then does something different in each case. But that doesn’t seem like good practice
@@orangeguy5374 Not sure how to ideally represent in languages like Java which lacks algebraic types.
But from what I've found you can represent it in two ways:
On a data level, you could a EnumSet or other way to define all your types of data with a corresponding flag and use its methods to check for intersection/union. Of course this is not ideal, as it would be preferred to have built-in language support.
I also think there are ways to represent intersection types as least with generics, interfaces and constraints. But I am not a Java developer, so I can't speak of how that would be done on a type-level.
I wouldn't overthink it though, because it can quickly result in unnecessary abstractions that makes it all more cumbersome to work with and maintain.
@@dealloc
Actually, I would argue that Java is now a language with almost full support for algebraic types, ever since the addition of sealed classes and records. Funnily enough as Java is seen as the hardcore OOP language with little functional support. Anyway, my question was more about how the idea of composition over inheritance ties into all this. How does composition help you implement algebraic types?
I’m a huge fan of your videos, and was talking with some coworkers about your “never nesting” video a couple weeks back. Turns out a lot of us had seen it independently haha. You’re getting some great traction!
Great content presentation. I am referring this channel to all present and future junior devs I'm working with. Bang-on about premature optimization and the link to inheritance. The common distinction between a choice of inheritance over composition is the "Is-A" vs. "Has-A" distinction. Inheritance leans towards situations where one thing can be directly and completely represented by a base. The classic dog or cat is-an Animal. Unfortunately these decisions tend to get skewed when your perception starts looking for these optimizations early. It becomes a hammer looking at everything as a nail. I've seen scary situations where things like customers, users, and offices extend a base address type just because they all share an address. This should be a "has-a" relationship, where those classes all "have" an address, Composition. Composition is generally easier and safer to optimize for as you go. Inheritance is an optimization I prefer to encourage as a later re-factoring once the "what" everything should be has had a bit of time to settle. +1 on the grins hearing Pee-En-Gee referred to as "ping" :)
I've watched a lot of programming videos over the years and I've gotta say, your presentation is second to none.
In a class I just finished, our final project was a 2D arcade game. The class was “Object Oriented programming”, and we used c++. We ran into this problem as we wanted to add features to our characters. We refactored to an Entity/component based system and it was such a relief. Minimal inheritance, mostly aggregation. Inheritance feels like OOP just trying too hard.
suddenly everyone hates inheritance like it’s some guy who shit in their cereal. Can’t we just recognize the best tools for the job and not demonize anything ? Sometimes I wonder...
Ah yeah, projects in uni. We spent days on the fucking class diagram and in the end it still didn't work out as we planned.
@@turolretar I think the reason for that is that many people use inheritance incorrectly, or use it in situations where it shouldn't be used. Just like OOP is often hated. I've seen people hating on OOP and Java and when asked to see their code, they reveal one massive god class with all members public. Of course OOP is bad when done wrong. But to be fair to people hating OOP: in my experience, many books and tutorials on OOP aren't very good at teaching the core principles.
@@turolretar That's the thing with people -- they like and dislike what they're told to like and dislike. As a JS dev, I'm so tired of people praising such and such framework because they heard someone else say it's the best.
@@turolretar The problem with inheritance is that it tries to do code sharing and polymorphism at the same time. There are already great tools that take care of those problems individually - and better. Want to share code between classes? Use composition! Want polymorphism? Use interfaces! Want both? Use both!
I've barely seen any real-world scenario where inheritance is the best option. You're adding a hard-wired dependency to your class for no reason. I find it's easy to paint yourself in a corner when relying on inheritance.
this content is like a polished gem. whenever I get recommends like this.. It feels like I have found a Lush Cave.
waiting for the Dependency injection video
Love this channel! This is the exact visual representation and walk through of concepts that all books and articles lack. When are you coming out with that dependency injection video you teased about? Really looking forward to it!
This is how programming tutorials should be done. I have never seen anything better in regard to clarity, visuals or consistency. I only wish there was hundred more videos to watch. =D
I've seen class/inheritance coding before in large projects, such as BioPerl. File reading/writing are their own classes. Data storage are another set of classes. Each uses some amount of inheritance to work. For example reading/writing a FASTA file vs a CSV vs Etc... all have a base class to work from and the data held being a Seq, RichSeq, etc... also have their own base class to work from.
What you did in the video mixing reading/writing with the holding/manipulating is what creates the real problems when trying to use classes and inheritance :)
The 'aesthetic' part of the channel name is very true. The whole video is so pleasing, not only visually
Holy crap this channel is liquid gold. I'm entirely self taught and have always been a little in the dark when it came to proper abstraction and inheritance. This clears it up soo much! Can't wait for the next upload.
Interestingly enough, just yesterday I was trying to formulate in my head when I would use inheritance vs composition, and the answer I came up seems to be in line with your video: Use inheritance for designing well defined interfaces, and composition for just about anything else. Thank you for making this video. I intend to show it to some of my newer-in-industry coworkers.
It's worth pointing out that there are a great many different applications of programming, and not all of them lend themselves well to every paradigm. Generally speaking, I think Object Oriented Programming, and inheritance, are very powerful when writing or consuming a library with a public-facing API. The ability to create a set of classes which can be inherited from, and the ability to extend the classes in an API, are quite valuable. But most application code tends to benefit more from a functional or procedural design.
The graphics at 5:46 display your point incredibly well, nice job!!
A good approach is to use interfaces first, that way you declare what is necessary. Then if you really need inheritance, you can make an abstract parent class that inherits from the interface and contains the boiler plate code you want. This way, not everything that implements the interface also has to inherit all the functionality as well. That can stay restricted only to subclasses where it is actually helpful. Still it is better to avoid this most of the time. Interfaces are fantastic though
One of the better cases for using inheritance is to provide extension points to override behaviour in a class. Using the image example from the video, a TIFF class may provide an extension point to allow additional meta data to be written into the class. Similarly, the PNG and JPG classes may be subsclassed with WaterMarkedPNG and WatermarkedJPG classes....where all behaviour is the same, except when streaming the image. You could do this with composition, but it is far easier with inheritance.
@@jimiscott Yes, easier to implement initially with inheritance, due to less boilerplate. But you trade off flexibility. Consider that some requirements change for the parent classes, but should not change for the subclasses, then you now have an incompatibility, and in an ideal world you would decouple them. But time is money, so you end up patching it by overriding all subclasses to ignore this requirement, or over-abstract the entire thing, ending up with more debt.
We have to consider what would happen in the real world, rather than what is theoretically possible, if we had infinite time to do things.
Of course it could be considered on a case-by-case basis. But sticking with composition will make things much more easily manoeuvrable, even you tradeoff by having to write extra boilerplate.
Thank you for this. Due to the types of projects I code, I'm constantly struggling with the inheritance refactoring woes you speak of. I have a serious case of imposter syndrome though, and just assumed I was doing it wrong. I've since switched to using the composition method you went over, but wasn't very strong in its fundamentals...and assumed I was doing IT wrong as well (which in some cases, I was). Laying them out like this is exactly what I needed, and you saved me hours of trial and error due to a combination of incorrect assumptions and a lack of a strong foundation.
Seriously, thank you.
It would be so great to also mention more technical terms for this, like the Dependency Inversion Principle (related to using interfaces), Strategy pattern, etc.. Yeah, you gave a brief explanation of why it is useful, but just throw another bone to the devs who want to find out more about the topic more easily.
I wrote an image class just as an exercise about 25 years ago. It was the best lesson on the limitations of inheritance (and templates) I could have ever wished for.
Yep dependency injection and interfaces are a great solution. But it's worth noting that more strategies exist.
C# has also extension methods, which are basically static methods, but used with a notation of actual methods.
And the Rust language has a very interesting typing system which is based on so called traits, really worth to learn about.
But if I choose to use inheritance, I will do it only in the same project for a small set of classes, but not for public library code.
And only just a single base class, expecially no deep interitance trees. Keep it simple.
Last note, methods in C# are sealed by default (you cannot even use that keyword). This differs from Java.
But you can make your classes sealed as well, but which is not by default by the language and which is a very good practice to do by yourself.
As someone who has been trying to understand what inheritance was in the first place for a while, or why it would be used, this video helped me greatly!
and THEN you beautifully describe what composition is as well!
As with most examples of problems with inheritance/OOP, I feel that the example used here and the particular way that it breaks down is more of a design problem, less of an OOP problem. The three format dependent classes really don't make much sense as subclasses in the first place - why do I care about JpegImage if the only JPEG specific part is how it loads and saves the file? In memory, all the images are the same, so there isn't really a reason for them to not all just be Image. The compositional approach works here, but I would go another direction.
Create an ImageFileHandler class, and give it methods for each type of image. Give the Image class an imageFileHandler, have its save/load methods delegate to this. Technically any image could be saved to any format, so we should go ahead and add a parameter to save to specify the format, and/or include a property the remembers the original format. But for loading, why not just detect the format by file extension.
Now we have an Image class that can load/save images in any format without the user even needing to think about it. New formats can be supported by updating ImageFileHandler and Image doesn't even need to know what the format was!
Alternatively, instead of embedding the file handler inside the Image, a new ImageLoader class could be created, and it would be an Image factory - the load method would return a new Image, and the save method would take an image as an argument.
Precisely, the example was poor.
UA-cam recommended this video to me again with no indication that I had already seen it. And I was thinking exactly the same thing I was thinking almost a year ago, scrolled down to comment, only to see that I already had. Very strange feeling.
can you believe this guy only has 4 videos on his channel , wow, we need more man, more. Also code snippets of videos, would help me and am sure any see those differences and appreciate your content better. thanks man.
Loving the growth of the channel! Keep making these videos!
One note, sometimes it can be hard to tell which lines of code you are referring to when the screen is full of code. Play with ways to focus attention where you want it to be. I found myself having to watch a few segments multiple times to notice everything you were doing onscreen.
I have been really confused by how to implement Interfaces basically since I started learning about them. Thank you for explaining this in a way I can finally understand!
Inheratance was incredibly useful for me once. The most interesting comment I have heard about it went something like: "My the time you understand enough about the problem to use inheritance, you have already coded the entire thing"
And that is my experience. It is hard to use because it requies a more complete understanding of the problem than we have most of the time, and we don't use it very often, and it is the sorto of technique that even in programming class you will never be given an example of when it is actually useful, instead you will be given a few hypothetically situations where using it is possible but quadruples the amount of work to solve the problem.
Inheritance is the perfect way to solve quite a few problems, but it is not practical 99% of the time.
Very good points. You have to constantly be going back to see what the parent does only to find out that it's that parent's parent that implements something. You have to maintain an awful lot of crap in your head at once.
No. Simply put, inheritance is a powerful tool that needs experience to be used properly. The design described in the video is deeply flawed, it's an antipattern and I would scold if any of my guys do something like that.
I wish I had a channel like this to look to when I was trying to step up my game from a programmer who just knew how programming worked to a programmer who knows how to write code the right way. Despite being a professional for quite some time, this still really solidified a lot of things that I've already learned myself and makes me feel a lot more confident about the design ideas I've already made (and maybe question some of the ones I've made in the past).
A++ recommendation for anyone trying to get out of the shackles of being an intermediate programmer.
Composition is for services, inheritance for entities. End of story.
Beautifully done. Not only the code is Aesthetic, also the voice, editing and storytelling ❤
Best upcoming channel ngl
A very nice channel and the comment section is worth reading to. I think one of the things helping with this is that design is often a balance , and your videos acknowledge this. Humans can often get “religious” or “political“ by thinking there is one right answer, but this really shuts down your thoughts and the conversation. Good job.
One additional factor that makes composition preferable to inheritance is in cases where an inheritance tree grows deeper and more complex and you want to share code between two branches that are otherwise unrelated. You may be able to deal with most of those issues with more inheritance, but they will be incredibly convoluted and confusing. In some cases it may be impossible to achieve.
also if you need to change the hierarchy one day (because one of the traits modelled through inheritance will be removed, and some other one will be added).
inheritance hierarchies are notoriously unflexible, so such refactoring will create a powerful domino/ripple effect throughout a codeabse (if it relied on inheritance a lot).
with composition this impact is limited to a minimum.
Composition can grow unmanageable too, if done wrong. Any tool can be abused, but that doesn't make them inherently bad. Try to use a knife as a screwdriver, and it will kind of work, but not well. Try to use a screwdriver to slice bread, and it will perform horribly.
I found that you can't just follow exact rules blindly, programming is too complex for that. The best you can do is having core principles that are vague and contradicting each other. That's why programming hasn't been automated yet.
@@andrasbiro3007 sure. But, in my experience, inheritance is the tool that gets abused the most and most often. And abuse of composition can make code difficult to read and understand. Abuse of inheritance can make certain changes or improvements impossible without what constitutes a complete overhaul.
@@Vendavalez
Difficult to read also means very hard to change. Don't blame the tool, blame the user.
I've been using inheritance extensively for like 35 years, and never ran into big issues.
I refactor the offending code long before it can cause big problems.
@@andrasbiro3007 two questions for you. Are you the only person working with your code base? If the answer is no, now many of those people are juniors?
I never understood the purposes of inheritance and interfaces and why you would use them at all. This did a better job at making me understand it than my university did.
This is like Fireship but with more complex and in-depth videos. Great work!
this is *so much better* than Fireship
can't believe you compared this legend to fireship
@ghost mall like Fireship as in high video production explainers for dev stuff.
Both channels produce good content but serve different needs/functions.
I see that you switched from blurring out the unfocussed portions of the code (as it was in your previous videos) to darken them, as to emphasise the relevant lines that you are discussing. This makes it so much easier to follow your explanations. Thank you for being open minded and listening to your audience's suggestions. Great video, as always.
This is perfect, I'm loving the Oriented Object Programming series.
Are you planning running through other topics like Data Oriented Design or Functional programming?
I, too, would love to see videos on data-oriented design and functional programming.
Darkening the unimportant code part is much appreciated. Thanks
I saw all your 4 videos today, and I'm sure I will keep watching your content. +1 sub for you!
I haven't seen any info about who you are or where your experience come from, but to me, it looks like you're learning much by yourself, because as far as I know as a self-taught dev, you don't tell people to code the way people learn in school, you tell people to write code that actually makes it easier for everyone to read and understand the code, even for non-devs
I'm used to teach people, help people and learn how to improve my code, and with that experience, content like this makes it so much easier to explain to other people why I write code the way I do, because you literally explain in depth the reason for why my coding style can be so good, which I'm 100% sure is your coding style as well :P
An excellent summary of the real world issues with the different techniques discussed. Appreciated. Thank you for sharing.
Abstract classes and interfaces are not mutually exclusive. I would claim that the two serve completely different purposes. Often I define an interface for the bare conceivable minimum for a certain entity, then have an abstract class implement most of the interface and finally having a couple of specific final classes for the current known implementations. This pattern has yet to come back and bite me. I would never refer to the abstract class directly as an argument, property or similar. I only use it as a path to reuse code.
Dude this was the video I needed. Have been working on a new code base at work and the architect has introduced an absurd amount of inheritance. I've really struggled working on it and this video has given me the counterpoints / system design ideas to push back a little stronger. Thankyou!
1:07 bro really called it "ping"
Where were you man for so long....
This world needs people like you, be consistent and keep posting....
I've been wanting to learn how you animate your code. Or mainly, how you get highlighted code like this that's also easy to animate.
I know my way around DaVinci Resolve's Fusion but that seems like an imperfect solution for this.
Could you shortly elaborate how you achieve your animation? That would be a great help in my learning efforts and might get me back into making some programming videos again :).
Thanks a lot and please keep on delivering such quality content.
Great video. I like that you exposed and solve the problem with the same code base.
Most of the time a complex problem is exposed but the author is switching to a different codebase to expose a solution.
Good composition is preferable to bad inheritance, but good inheritance is preferable to good composition. If you're defining your inheritance properly it shouldn't have the drawbacks you stated. But, like anything, it can be done wrong. I hate coming into a codebase and seeing things like "ImageDraw" because that's only part of an object. It's not a thing, and it's not clear what it's modeling, or what it does. If you model your image class hierarchy correctly, they should be intuitive to understand, which you lose with composition.
Bro.. I dedicated my life to learning and dev since I was 8, and I gotta say you’ve got such a finessed approach that is easy to digest and retain simultaneously. Well done, my friend, well freaking done!🎉
Even though you don't have many videos they are really high quality and explains the different coding concepts very well.
Dude, you just transformed something that is so hard to grasp into something so much fun to learn, well done 👍
I don't think I've ever heard anyone pronounce PNG as 'ping', and honestly I was happy keeping it that way
I don't think I've heard anyone pronounce any other way than "ping".
@@eckligt it's PNG, you pronounce it letter by letter.
Edit: maybe it isn't
@@jbritain According to en.wikipedia.org/wiki/Portable_Network_Graphics you're wrong, and actually even according to libpng and w3c (source 2 and 3 in the footnotes on that Wikipedia page) you are also wrong.
If you're gonna be assertive, at least be correct.
@@eckligt I mean the creator of the gif format pronounces his own format incorrectly 😉
The "official pronunciation" of PNG honestly looks like a nod to the intended/proposed name "PING" to be a recursive acronym to mean "PING is not GIF", though that's only recursive if the name remained as "PING", which it didn't; it ended up being named "PNG" which SHOULD come with its own pronunciation. I imagine it stuck since without a vowel to make it feel like a "word" like JPEG or GIF they wanted a way for people to say it quickly and easily but in a world where people just read "png" on their screens we see that's not the case.
Language is supposed to evolve, and that evolution often follows the colloquial path.
@@eckligt I stand corrected!
The demonstration style in this video is incredible!
It’s strange talking about composition without dependency injection. My understanding of composition is that objects are ‘composed’ of other objects/interfaces. This allows for more straightforward initialization, maintenance, testing and extensibility (among other things)
Your first example of composition, a common class was passed to the signature of a method of three independent classes, which to my understanding, isn’t composition (correct me if I’m wrong)
It almost seemed a bit backwards where if you wanted a compositionally alternative to your inheritance example, you’d have an image class with with an image processor interface in it. From there you’d have an image processor for jpg, bitmap, etc… (not saying I like this way better than your way)
But your second example of composition with interfaces aligns better with my understanding. Again, correct me if I’m wrong. I could be too dependency injection brained and can’t remember alternative ways to build compositionally
Id argue it's still composition, but you end up composing on the method level rather than the class level, which might or might not be preferable
I think the example of inheritance was weakly designed on purpose, in order to refactor it cleanly; the initial concrete class has too many responsibilities.
The first example of composition @4:33 may be a bit misleading : there is NO composition between JpgImage and Image because their lifetimes are unrelated. In a true composition, one class have the responsibility to destroy the other when it's destroyed itself. Here it's a simple Dependency, JpgImage uses Image, but Image is not a structural part of ImageJpg or vice versa so it's not an Aggregation.
In the second example of "composition" @4:50, there IS an Aggregation between ImageDraw and Image, ImageDraw has an Image as a part of its structure. However there is no indication about their respective lifetimes. So we should not say it's a Composition as per the UML definition, but it's close enough for the purpose of the video.
Even if we push an Image in the constructor of ImageDraw, it is NOT dependency injection. The purpose of dependency injection is not to build a composite object, it is to inject an interface (instead of a concrete class) into another class in order to cut the dependencies over a specific implementation, and to facilitate testing (using mocks instead of an actual database, a physical file, or a webservice for example); nice example of DI @8:01
Usually composition refers to an entity having an array of components which makes the entity agnostic to its own properties. Only external systems would be able to work on each individual component of the entity, hence we have composition since you can define a male/female as components of the composition and have them accessed only by the "sex" behavior systems
This is not what I'm thinking of when I hear composition either, to my ears this sounds more like the kind of service-oriented programming that is popular today (for good reason - it's good). Composition as I recall it tends to suffer from the fact that the composed class may need to restate all the desired methods, with the body of the restated method simply calling the method on the property which implements the desired functionality.
Even the wikipedia article on on this ( en.wikipedia.org/wiki/Composition_over_inheritance ) states:
"Composition over inheritance (or composite reuse principle) in object-oriented programming (OOP) is the principle that classes should achieve polymorphic behavior and code reuse by their composition (by containing instances of other classes that implement the desired functionality) rather than inheritance from a base or parent class."
@@airen2 Only way for true composition is 180 degree turn away from OOP into the unknown lands of DOP (Data Oriented)
In all my years of professional programming I've used Composition over Inheritance like 95% of the time but never really thought about much of it. Thanks for giving me something to think about and love the channel man; keep up the good work.
You still inherit base class for BmpImage in 4:44. Also I think t's kind of weird "in between" way to implement this - holding path as property while passing Image by reference, and mutating Image during load. I would personally either make these classes completely stateless ( void save(Image image, string path), Image load(string path) ), or also hold ownership of Image as class member. Nevertheless, concept by itself is exceptionally explained - great job!
Then it starts to become closer to the better pattern, which is to go Functional.
You are the kinda youtuber that has so high quality videos that i watch even though i dont even code ever
Could you elaborate on why clean relational DB schemas are bad for scaling and why you switched to NoSQL to fix that?
They're not bad, it's just the common trap many devs fall into when it comes to "WORKS AT SCALE". Relational DBs can be scaled and run as nodes just like NoSQL DBs. The thing that truly puzzles me is that some popular NoSQL DBs have terrible transaction handling which should make devs terrified of using them in production, but people don't think of that.
Subscribed. Video was comprehensive and comprehendible. Helped me realize something I haven’t formally seen before. Thank you!
Interfaces have the potential to recreate the same problem that inheritance causes. It makes your code less maintainable. If an interface is ever changed, then all classes that implement it must be changed as well. Using interfaces to allow for polymorphism in your compositions can potentially create just as many problems as inheritance. Both can allow for maintainable code if implemented correctly.
In your images example, inheritance wasn't done correctly and that is why there is a problem with the save/load functions. The designers of the image class should have acknowledged that there should have been another class between those in the inheritance tree. Their design assumes that all images are "savable." A SavableImage class should be between the Image class and the children. Or, in my opinion, a savable interface should be implemented because savable things are not always images and therefore other classes could also implement those methods.
I feel like most of the problems people have with inheritance is because there simply isn't enough layers in the inheritance tree to describe the changes between parents and children. If careful thought is put into the maintainability of the code at the time of design, a lot of issues like this particular one can be avoided. Not saying that inheritance is infallible if done correctly, it definitely can be used incorrectly. I just think too many people avoid the concept because that's the latest fad, and the real issue is that people need to spend more time on designing their ideas instead of just coding them.
Good points! I think one of the main reason for people misusing inheritance is the damaging rule-of-thumb I've encountered so many times, that inheritance shouldn't be more than one level deep below the base class. If followed strictly, one ends up with the problem you describe. I agree that the example in the video has an excellent example of having Saveable as an interface and an Image as a base class which knows nothing about saving and loading itself. It shouldn't be the responsibility of the image to know how to save itself.
Best explanation of object composition vs inheritance I have seen so far, great example makes it easy to understand the conceptual differences and pros and cons here. Thanks for a nice video covering this!
One thing that puts me on "inheritance always sucks" side is many times you'll have multiple shared behaviors which don't align with any hierarchical structure. A child class cannot inherit from multiple parents, but it can inherit from multiple interfaces (typeclasses, traits, etc.). A quick example:
Let's say you have three classes: Bike, Car, Helicopter. Bikes and Cars have wheels, and Helicopters and Cars have baggage holds. You want to write methods that handle baggage holds (put stuff in and out) and wheels (rotate them, count them, etc.). It is impossible to create appropriate parent classes for this purpose - you would have to have a parent class for Bikes and Cars to inherit from, and one for Helicopters and Cars to inherit from, which is impossible with classes (because Car inherits twice) but not interfaces.
You can't make a parent class that encompasses all those behaviors either, because then it would have to have useless functions for some of those subclasses and throw errors/panic/etc. when you call them. Because this structure is not hierarchical, where bigger concept contains smaller concepts, but instead you have concepts that overlap for some thing and don't for others and structure is disjoint, inheritance is completely inadequate to handle this scenario, even though it's fairly simple.
If we'd learned anything from database programming, most things are linked chaotically and not at all in a hierarchical structure. Your data structures can share traits with many other data structures that don't contain it or aren't contained within it. This is why I like that Rust has no inheritance for structs - if you want shared behavior, use traits to describe it. This allows Rust to describe shared behavior even for built-in types, where a lot of them are composed of various combinations of traits.
I feel like, in this instance, it would probably be best to make a Wheel class and a BaggageHold class, then make those members of the Bike, Car, and Helicopter classes, accessible with car.wheels or helicopter.baggageHold. However, some languages have multiple inheritance or mixins which could also be used to solve the problem
"a child class cannot inherit from multiple parents" - in C++ or Python it can.
@@-Jakob- Yes, and that causes its own problems.
@@michaelmounteney2034 yeah I don't use it, more confusing than it helps.
@@tomysshadow Sure, but that's composition. And imagine you can't do that, let's say you have wheels and axels. Both rotate, so you have to make a stupid class RotatingThing, that defines a method rotate(). But wait, that's basically an interface
I love the change from blurred code to highlighted and dimmed code. I found this much more legible and easier to follow.
Please don't burn out on these. I think you're filling a niche that is poorly served elsewhere, I hope you've got a long future here.
I was a little concerned you wouldn't mention any of the cons of composition at all, but you eventually did, although its likely late enough in the video where a lot of people wouldn't have seen it.
Particularly with large scale projects, inheritance becomes much more important, as you alluded to in your pros and cons list.
Your videos are unbelievably good-everything about them. Thank you a million times over.