 What's going on YouTube? Lee Brandt here with OctaDeveloper. Today we're going to talk about default implementations in C-Sharp. Why I hated them, what I heard about them, but now that I've played with them a little bit, kind of love them. Let's check it out. Now, Microsoft introduced default interface methods a while ago with the release of C-Sharp 8. If you're like me, when I first heard about it, the first thing I thought was what do you have against abstract classes? I mean, isn't that what they're for? To provide an implementation at the very base of everything? And the problem comes in and the reason that this is necessary is because C-Sharp doesn't support multiple inheritance. And most languages nowadays do not support multiple inheritance. I think C++ might still. But the reason why is because of the diamond problem. And this is just one of the problems with multiple inheritance. So let's say for instance, I have this D-class. And D derives from both B and C in languages that support multiple inheritance. So both B and C inherit from A. Now A has a method on it called walk. Okay, whatever. C overrides the walk behavior. And then when you call D dot walk, which implementation am I using? Am I using C's implementation of walk? Or B's implementation of walk? Or A's implementation of walk? So what you'll get usually is a compile time error saying unspecified implementation. So basically what you end up having to do is you have to decide at design time whose implementation you're going to use and you have to specify it out to the end's degree. So default interfaces methods don't totally get around this. There's still a bit of a problem there, but it does make it a little bit easier to implement this. But that's really the reason for default interfaces and not just using abstract classes because if you've already got a class that derives from another class, you can't inherit from another class. So you have to add in, and you can have multiple interfaces. So since you can have multiple interfaces and they're already there, that seemed to be the best place to put these interface default methods because then you can actually do something that's known as trade programming and add some traits to classes that already exist. Let's see how that's done. So let's look at what default implementations or default methods and interfaces actually gets us. Why would you go through all this trouble to get it in there? And there's this thing called trade programming and it's a way to add functionality to a class that already exists without kind of modifying the class. It's just a way to extend an existing class and give it new capabilities. So way back when you first started developing the application for your company, it's a young company, you're young baby-faced developers and you only know what you know about the business and about what your needs are going to be. So this, again, is a contrived example but it boils everything down to its essence. Don't focus on the fact that I'm using a file stream that I haven't initialized, just trying to make the code small so the examples come out. So I've got the iLogger here and it's just got one method, log, that takes a string message. Then I've got a file logger class that implements the iLogger interface and it implements that log message, log method by taking the message in and writing it to a file stream. Now this is all fine and dandy until the system grows some and now you need to be able to log things differently. Maybe you always want to log errors to file logger. Maybe you always want to, maybe you want to load, log errors and info and just plain old system messages and warnings and all that stuff and you want to log them differently. You could start by trying to come up with some standards and saying that errors are going to be logged with the square brackets and error and then colon and then whatever the message is. But then people write a piece of code and since strings aren't compile time checked or runtime checked, you have to go and find out why this error is missing a bracket on the end of it or really what's probably happening is you're searching through this big text file and you're not seeing an error that you should be seeing open square bracket, error, closed square bracket, colon to find all the errors in this big text file. So then you have to start backing that off and trying to figure out maybe somebody misspelled error in one. Okay, now you have to try and figure out which class is writing that error, how do I go and fix it and make sure that it's following our standard, blah, blah, blah. There's easier ways to do this. I could go back and add a log error and log warning and log info to iLogger and then I have to go and find all the places that implement iLogger, like the file logger, the database logger, the Mongo NoSQL logger, the Splunk logger, whatever it is, whatever loggers you've created that implement iLogger, you have to go and find all of those and implement log error, log warning, blah, blah, blah. When really all you really wanted to do is log but you just want to log it with a specific format so that it's easier to find in the file log. So what we might do is we might come back and implement those as default implementations in the iLogger interface. So log warning just calls the log method right up here. It just adds warning at the front of it and for log error it just adds error. So now we have this implementation in one place in the iLogger and the file logger still works the same way. Nothing changes in the file logger. It just does log, file stream, write line, message. And what ends up happening is whenever somebody who's using it calls log warning it adds, it calls log with warning at the front of it and the message piped in and this is the implementation that gets used because this has no implementation. So it's not going to use the iLogger's implementation of log. File logger is the one that has that implementation. Database logger is going to have its own implementation where it logs the type of error message in one field and it does a SQL statement to insert that into a record into a table somewhere. And none of that has to change in so that means that when my iLogger gets injected into some controller somewhere file logger is the one that gets injected via my dependency injection container system and so the logger is actually a file logger. So when I call log error, file logger doesn't have a log error method but it kind of does because it implements iLogger and there is an implementation that gets just all the way down here in iLogger. Now you still could have the same problem where you implement iLogger in two different places and you inject both of them in there and you're still going to have some of those same diamond problems. They're going to cause a compile time error saying that it's an ambiguous implementation and you just go in and you say the file logger's log error. But the log error doesn't necessarily have to exist in file logger, you just have to treat it like a file logger and the file logger implements iLogger which has the default implementation if that makes sense. So you haven't gotten rid of all the problems that come with multiple inheritance but you've really simplified it and you've allowed people to add this trait. So you might think at this point okay default methods are cool I can see their use but isn't that a little dirty? I mean it feels a little dirty to me to put implementations in my interface and is this something that I can use as a quick fix but I should actually go back and change my class architecture later to actually be more in line and not use the default implementations. I think both are valid points of view for me. I struggle with both. I think that this is a really good way to do a quick fix. So if you need to add this log warning log error you need to add a method with a default implementation like this I think it's a good way to get that functionality in there without a super heavy code lift and maybe you might decide that yes we need to go back and create a story set aside some time to actually re-architect this piece and it's going to be a little bit time-consuming because we're going to have to go and find all the places that implement iLogger but what if and this is what I keep turning over in my head what if we actually embrace default methods what if we designed our system with that in mind we know things are always going to change and not just from the business side that's the thing that most people think of when they think of change in an organization and change in a piece of software is that the industry changed and some new thing came down the pike from the business and I need to implement that in the software and that's common yes but there's also things that we don't really take into account we know that that change going to happen but there's also other changes that we forget that are going to happen like changes in the language that you use what if in this case C-Sharp 8 has default implementations in it for interfaces to leverage that or what if some feature that we relied on heavily and C-Sharp goes away it's causing problems in too many systems we haven't had a problem with it but C-Sharp is going to deprecate that feature now we need to figure out a way to change that those changes are going to happen the other type of change is going to happen is you're going to learn I mean you're here watching this video so I'm assuming you're learning anyway you're going to learn some new feature like default implementations that you didn't know about you're going to learn about some new way of doing something in the language that already exists it's not a new feature in the language it's just something that you've never used before you didn't even know was there but you talk to some of your programming buddies or you watch a video and you're like oh no you could do that that would be super helpful in here and over here and where we're doing this and this problem that we've been having over here where we've got this super convoluted code we could boil that down to one method class and be done with it so you're going to learn things are going to change so if you decide to use default implementations it's just another lever you can pull that you've got on your code to plan for that change just another thing that you can use that can make change easier and if you want to go back and re-architect the whole solution later for sure I mean that's not a problem at all but this is just a this is something that you can use in the meantime so I hope you've learned something from this I know I learned a lot from as I started digging into it man I need to write about this because I had no idea that these were actually kind of useful so if you found this useful please give me a like and subscribe down below hit the little bell icon if you like this type of content subscribe and hit the notifications icon so you get notified when new content comes out we generally publish new content on Tuesdays and Thursdays so you'll be the first to know when new content comes out if you like the stuff we're doing please let us know if you have a question please post it in the comments below I'll try and answer all the questions that are down there thanks for joining me today and see you next time