When Microsoft Violated Liskov Substitution Principle in .NET

  Рет қаралды 40,753

Christopher Okhravi

Christopher Okhravi

Күн бұрын

It's easy to paint yourself into a corner where you end up violating the Liskov Substitution Principle. Let me show you an example of when Microsoft violated the principle in .NET.
MORE ABOUT LSP:
• Liskov Substitution Pr...
📚 geni.us/IBhtLnh (Clean Architecture)
MORE ABOUT ITERATOR PATTERN
• Iterator Pattern - Des...
CHAPTERS
00:00 Intro
00:36 Overview
02:07 The hierarchy
06:49 Read only
10:16 The violation
14:17 Confession
17:43 Conclusion

Пікірлер: 315
@francisadediran6311
@francisadediran6311 Ай бұрын
"The whole point of static typing is to move error from runtime to compile time because that makes the code safer". Words of a genius
@drcl7429
@drcl7429 29 күн бұрын
Don't know if you're being sarcastic. That is precisely why static types exist and why I very strongly dislike dynamic and weakly typed languages. You have to think too much about what might go wrong. You already have to do that plenty.
@francisadediran6311
@francisadediran6311 28 күн бұрын
@@drcl7429 Not being sarcastic, just highlighting a very good point which i have forgotten
@ChristopherOkhravi
@ChristopherOkhravi 26 күн бұрын
I cannot take credit for this since it indeed is the very idea of static typing. Nevertheless I find it very important to keep reminding ourselves of that 😊😊 Thank you both for watching and sharing your thoughts 😊🙏
@_iPilot
@_iPilot 17 күн бұрын
This is why TypeScript has appeared. An attempt to relief all the pain related to JS brining a bit of static to the primal chaos.
@Bobbias
@Bobbias 13 күн бұрын
​​@@_iPilotexcept that there are too many ways to escape the static typing in typescript. It's an improvement over js, but still ultimately just papering over the gaping holes in js's type system.
@demarcorr
@demarcorr Ай бұрын
I *promise* you, cross my heart, swear to god, or smite me now, I violate every single SOLID principle, every single day, without fail.
@ChristopherOkhravi
@ChristopherOkhravi 14 күн бұрын
😊😊😊
@krozaine
@krozaine Ай бұрын
What a roller coaster ride in the explanation, especially with the entry of isReadOnly. Super awesome take on the issue and explanation!
@ChristopherOkhravi
@ChristopherOkhravi Ай бұрын
Glad you enjoyed it! 😊 Thanks for watching 🙏😊
@amerbashoeb2106
@amerbashoeb2106 Ай бұрын
I just cant you thank you enough. There is no one on KZbin who teaches like you do. Thank you brother.
@renatogolia211
@renatogolia211 Ай бұрын
To be fair to the .NET maintainers, certain types have been added later than others and they didn't want to break backwards compatibility. For example IReadOnlyCollection and IReadOnlyList were added in .NET Framework 4. Unfortunately, ROC has always been the weird guy.
@BeatsByYari
@BeatsByYari Ай бұрын
another annoying thing is that Array implements IList in C#, but when you call IList.Add it throws an exception, so you can't be sure you can safely call .Add on a method accepting an IList
@Ockerlord
@Ockerlord 26 күн бұрын
So does IsReadOnly return true for Array then?
@modernkennnern
@modernkennnern 23 күн бұрын
It only throws if it's full, but yes. It's annoying
@markw.schumann297
@markw.schumann297 17 күн бұрын
But... but... what even is the purpose of implementing IList in ReadOnlyCollection? By what logic does one _want_ a "read-only collection" to necessarily also be a "list"? I don't get what the objective of that decision even was.
@ProjSHiNKiROU
@ProjSHiNKiROU 15 күн бұрын
For interface API design in general: If mutation is involved, interfaces should be split up into the reading part and the writing part (also works well with co/contra variance): IReadCollection and IWriteCollection. There are barely any use cases for write-only collections so that design isn't natural to most people.
@Tynach
@Tynach 3 күн бұрын
Why not make ICollection just behave essentially the same as IReadOnlyCollection (and inherit directly from IEnumerable), but then have IWritableCollection inherit from IReadOnlyCollection and add just the stuff for writing to it?
@user-ut8sk3lc3c
@user-ut8sk3lc3c Ай бұрын
What a clear explanation of complex Liskov violation on more complicated hierarchy of Collections... Hats off!.!! 😊😅
@dawid_dahl
@dawid_dahl Ай бұрын
I will send this video to anyone who’d like to learn the LSP! 👏🏻
@ChristopherOkhravi
@ChristopherOkhravi Ай бұрын
Thank you 😊🙏🙏
@stardrake691
@stardrake691 27 күн бұрын
You’ve earned a new subscriber. Your explanation style is so unique and satisfying to watch, I think in mind the way you emphasize facts, and that’s why your teaching style is relatable to me.
@ChristopherOkhravi
@ChristopherOkhravi 26 күн бұрын
Thank you very much. I’m glad to have you 😊🙏 and I’m glad that the content is useful 😊
@quentinparis1113
@quentinparis1113 Ай бұрын
@chrisropher you should define the Okhravi principle: "never solve at runtime a problem that can be solved at compile time" 😊 By the way this is one of the best video I have seen on software development!!
@ChristopherOkhravi
@ChristopherOkhravi Ай бұрын
Thank you. Those are some very kind words 😊🙏 I’m happy that the content is useful. I can’t unfortunately claim ownership of the idea since it’s very old but I will definitely steal that wording and use it. Thank you 😊🙏 and thank you for watching 😊😊
@user-hg4fs2ik5c
@user-hg4fs2ik5c 15 сағат бұрын
Man I love you. I see that you're back on KZbin after years. I have encountered your channel after university bullied me into Software Design, but you made it slightly more tolerable. Anyways, thank you so much. I will be having my exam in two days. If I pass, it's totally because of you. Even mentioned you in the Course Review section of my course, as our course was probably the most boring thing I have ever seen. However, you made me see the beauty of it, even though I totally hated it all. You just earned yourself a permanent member of your community :)
@adambickford8720
@adambickford8720 Ай бұрын
Before cheating off java's homework, make sure it's right
@ChristopherOkhravi
@ChristopherOkhravi Ай бұрын
Underrated comment 😆
@sergtachini
@sergtachini Ай бұрын
Java has the same, Collections.unmodifiableList or List.of
@redcrafterlppa303
@redcrafterlppa303 Ай бұрын
The stupid thing is Java is even worse at this. They didn't even bother adding a readonly hierarchy. They simply added factory methods that create readonly collections of type (I)Collection
@streettrialsandstuff
@streettrialsandstuff Ай бұрын
Yeap, they went ass backwards, it should have been ICollection and IMutableCollection.
@andywong3095
@andywong3095 Ай бұрын
J-things expert, talking about c# and Dot-things.
@vincentjacquet2927
@vincentjacquet2927 Ай бұрын
As you said, Add throwing when IsReadOnly returns true is not a violation of LSP per se. But there is a violation of LSP for ISet that also specialize ICollection. Given an empty list of integer, when you add 1 twice then the collection has a Count of 2. Given an empty set of integer, when you add 1 twice then the collection has a Count of 1. Had the signature of the method been bool Add(T item), like there is bool Remove(T item), it would have been a completly different story.
@ShubhamKhara
@ShubhamKhara 19 күн бұрын
Again, that's not really a violation but a very specific, arguably confusing behavior of the Add method. You can call Add and it works, that's all you need to not violate LSP. Also, some degree of freedom is required when we are implementing an interface, not every derived class has to Add to increase the Count. In your example, Set allowing Add on existing keys is actually the better approach, otherwise your Set class would be throwing exceptions which ICollection doesn't define. Actually, Set being an ICollection is a rather good example of trade offs in Software Engineering. By not being overly strict with how Add works, we are utilizing EVERYTHING else IEnumerable and ICollection interface gives us, and that's a lot more useful then defining a separate interface for Sets just to make it perfect.
@vincentjacquet2927
@vincentjacquet2927 17 күн бұрын
@@ShubhamKhara I beg to differ. This is the definition of Add. It "Adds an item to the ICollection", so you expect wether the operation to fail (i.e. throw) or to succeed, meaning the Count increases. For ISet, Microsoft had to create a "new" Add method, returning true when the value is added or false when the value was already present. With this signature, the test for the contract is if Add returns true then the Count increased by 1. Regardless of the return value, calling Contains with the value must return true. This is not a trade off, this is an oversight. The trade off is that we have to live with it.
@ShubhamKhara
@ShubhamKhara 17 күн бұрын
Yes, that makes sense. I had my tunnel vision set on ICollection's function's signature and not ISet's when I initially made the argument. Thank you for the revert, appreciate it.
@janailtongoncalvesdesouza4160
@janailtongoncalvesdesouza4160 Ай бұрын
I just love the way you explain things. Great vid!
@user-ev9jg6ts6e
@user-ev9jg6ts6e Ай бұрын
Chris, you are fantastic. Highly appreciate!
@orterves
@orterves 11 күн бұрын
Without a doubt, the ReadOnlyCollection inheriting from IList is a mistake even though the interface is technically correct by throwing that exception. One thing I'd say in addition is, I hope no one thinks that technical validity means the correct approach to using IList.Add is to check if it's safe or otherwise handle the exception in the case of ReadOnlyCollection - we should still code with the assumption IList.Add is always safe to call, and if a client passes in a ReadOnly collection to that method, that's on them to fix.
@IroAppe
@IroAppe 15 күн бұрын
So basically, the LSP is kept, because ICollection was already broken, so ReadOnlyCollection can be just as broken. Oh the irony. It reminds me of the mathematical property that you can deduce anything from a false statement. Although this obviously has nothing in common with that, it makes sense - if you have chaos, you can deduce more chaos from it...
@michaelwikstrom
@michaelwikstrom 18 күн бұрын
This is a brilliant explanation of LSP ! I love C#, it is a fantastic programming language, but as every programming language there are always some quirks due to historical reasons. I have heard about this "issue" before, but never explained at this level of clarity. Please keep posting these videos, preferably also using C#
@AndreyRogozhnikov
@AndreyRogozhnikov 13 күн бұрын
Wow! Such a clear and logical delivery!
@ChristopherOkhravi
@ChristopherOkhravi 12 күн бұрын
🙏 Thank you for watching 😊🙏
@Misteribel
@Misteribel Ай бұрын
Another good reason to move to F#. No LSP issues (unless you seek them out). All functional datatypes are immutable by default (which implies readonly). It's so much simpler and more concise, once you made the paradigm shift. Rarely try/catch or exceptions and aprogram you can reason about.
@_iPilot
@_iPilot 17 күн бұрын
Until you have infinite amount of resources and they are almost free. In the real world, all computations have their cost in CPU time, memory, and amount of data transferred over the network.
@greob
@greob Ай бұрын
Great lesson, thanks for sharing!
@ZackJJones
@ZackJJones Ай бұрын
Thank you so much for this! I was thinking of mentioning it in your previous LSP video but I couldn't recall off hand where it was I ran into this. I even recall leaving a comment on an SO article that dug into it. I ran into this exact issue with either something from work or a side project I was working on explaining collection types. Anyways, thanks!
@JohnDoe4321
@JohnDoe4321 16 күн бұрын
IEnumerable, ICollection, and IList were added to .NET in version 2.0. IReadOnlyCollection was added to .NET in version 4.5. Is the inheritance hierarchy "wrong"? Yes. But doing it "right" would have broken the world. If you value ideological purity more highly than backwards compatibility, perhaps C# and .NET aren't for you. 😁
@phizc
@phizc 15 күн бұрын
Inserting an interface into an inheritance chain wouldn't break anything. I.e they could have made ICollection inherit from IReadOnlyCollection. The big problem though, is that the class ReadOnlyCollection was introduced in .NET Framework 2.0, long before the interface IReadOnlyCollection in 4.5. So at the time they only really had IEnumerable that it could sensibly implement. They decided to implement ICollection and IList too, and those can't be removed without breaking backwards compatibility. (I didn't bother with all the s. Too annoying to type on a phone.)
@fourZerglings
@fourZerglings 9 күн бұрын
There's a simpler example: arrays in .NET implement IList without support for Add or Remove
@lawrencejob
@lawrencejob 26 күн бұрын
Thanks for articulating this. It’s been frustrating me for years!
@CodingTutorialsAreGo
@CodingTutorialsAreGo 10 күн бұрын
I share your pain, though an even more fundamental violation is: IList list = new int[] { 1, 2, 3, 4, 5 }; list.Add(27);
@ciberman
@ciberman Ай бұрын
Amazing video as always!
@Scorbutics
@Scorbutics Ай бұрын
Collections are always a pain in the ass to implement, but I totally agree with you ! Java has pretty much the same problems with their "Collections.unmodifiableXXX" (List / Set / Map / SortedMap...) and they are also using exceptions. Next step: how would you implement it ? I guess using composition, either containing another container inside the ReadOnlyCollection. Or by splitting collection interfaces into "permission accesses", ReadableCollection (get / iterate) WritableCollection (add / remove / clear) ? Or both ?
@guai9632
@guai9632 27 күн бұрын
MutableCollection : CollectionMutator, ReadOnlyCollection
@jackwesleymoreira
@jackwesleymoreira Ай бұрын
Man what a great explanation of the LSP. To me one of the most complex principles to understand. Thanks for the video and for the great job explaining it in a way that makes sense.
@ChristopherOkhravi
@ChristopherOkhravi Ай бұрын
Thank you for the feedback. Much appreciated. And thank you for watching 😊🙏
@arjix8738
@arjix8738 Ай бұрын
wikipedia says "objects of a superclass should be replaceable with objects of its subclasses without affecting the correctness of the program" which is pretty clear to me
@IroAppe
@IroAppe 15 күн бұрын
It seems so complex, because there are a lot of theoretical terms and definitions to make it logically strict. But the meaning is quite simple: Obey subtyping. A square must always be a rectangle. Not every rectangle must be a square. And then abide by that in all conditions and objects of the class or interface you are designing. It's also basically helpful advice to developers to adhere to the subtyping contract: - Don't forget method parameter types and return types - Don't forget exceptions - Don't forget input value checks and return value range restrictions - Don't forget value restrictions on instance variables and properties - both statically, and over time from state change to state change Of course it has applications in theoretical CS - in order to make any logical deductions, you need a strict definition. But in terms of application, it shows you what to look out for, when designing inheritance/subtype hierarchies of any kind.
@damianradinoiu4314
@damianradinoiu4314 16 күн бұрын
Your channel is wonderful. Giving out hidden gems as insights for whoever is patient enough to hear them. Do you plan on ever continuing the design pattern series ?
@ran-j
@ran-j 7 күн бұрын
This video was simply fantastic, great explanation about LSP
@ChristopherOkhravi
@ChristopherOkhravi 6 күн бұрын
Thank you for watching 😊🙏
@yamogebrewold8620
@yamogebrewold8620 Ай бұрын
Thanks for a great explanation as always. My takeaways from this are: 1. A statically typed language gives you the capabilities to design robust software. But a type checker can not do all the work for you. It hands the responsibility to the engineer to make careful design decisions. 2. It was nice to see how applying LSP leverages the power of the compiler and makes the program safer at compile time. Lots of issues could be avoided if we crafted our systems with this in mind.
@zalvazar9080
@zalvazar9080 Ай бұрын
Great video keep them comming
@sagarbhosale3337
@sagarbhosale3337 Ай бұрын
Very well explained. Requesting video on Liskov Substitution VS Interface segregation principle.
@moristar
@moristar Күн бұрын
It's like the first thing that gets violated in OOP and probably the least important TBH
@qj0n
@qj0n 10 күн бұрын
I think there are 2 ways of thinking about read-only collections. On the one hand, these are generalizations of read-write collections, which only support reading. On the other hand, these are collections which guarantee they won't change. I believe MS devs have change their mind about it couple of times and here's the result
@samyakshah806
@samyakshah806 Ай бұрын
Hey, just wanted to let you know that the link on recommended books, placed on your website, is not working
@AerysBat
@AerysBat 11 күн бұрын
ReadOnlyCollection implements IList which is an interface for a mutable list. This means it throws errors if you call add() or remove(). MSFT added an “isReadOnly” flag in ICollection which allows add()/remove() to throw errors. It’s messy workaround for a LSP design error and weakens the compiler.
@johnekare8376
@johnekare8376 Ай бұрын
Great video!
@vinayshastri497
@vinayshastri497 Ай бұрын
@ChristopherOkhravi Can you please explain what could be the possible reason of Implementing IList by ReadOnlyCollection base class. I didn't get this part
@modernkennnern
@modernkennnern 23 күн бұрын
IReadOnly** was added much later - after they had made that big blunder with `IsReadOnly`. It's also because (and this might change in .Net 10) IList and ICollection does not implement their IReadOnly counterpart.
@jvesoft
@jvesoft 18 күн бұрын
That's one of the things I like in Objective-C. It's main classes are immutable: NSArray, NSDictionary; they have subclasses NSMutableArray and NSMutableDictionary. Though I don't know .NET, I think that the hierarchy of interfaces would have been nicer if the base interface IEnumerable would have a subinterface ICollection (without add/remove), which would have two subinterfaces: IMutableCollection (with add/remove) and IList (with get(index), but without set(index, item)). The interface IMutableList would have two superinterfaces: IMutableCollection and IList and would add the set(index, item). No need for "unsupported operation" exception and you can immediately see what the class actually supports by its list of interfaces.
@perian1983
@perian1983 Ай бұрын
Very nice video as always, it definitely was food for thoughts. Letting alone the discomfort I would have using an object of a class that could be (in theory) both mutable and immutable and letting alone the cognitive overhead in terms of counterintuitive naming, I could not help but thinking that this way of deciding the behavior of an object of a given class at runtime with an if-else block may be a little bit of an anti-pattern in a language that allows you to use types (at compile time) to address the issue. What I am wondering now is which reason(s) they may have had to make this particular design choice. Any idea?
@vchap01
@vchap01 Ай бұрын
.NET concrete collections have always been a mess. Collection implements List, SortedList implements IDictionary and those are the ones just off the top of my head.
@Nobody1707
@Nobody1707 18 күн бұрын
Coming from Swift, I'm surprised by that interface hierarchy. The equivalent protocol hierarchy in Swift is Sequence
@jvesoft
@jvesoft 18 күн бұрын
Wrote my comment (about Objective-C), before seeing yours about Swift. Yep, there are things, which Apple clearly did better. P.S.: Don't like Swift (I prefer Java nowadays), but it's definitely better than mixing C and Smalltalk. :)
@ShivamKendre-fc3su
@ShivamKendre-fc3su Күн бұрын
What a great video!!
@davidturner9827
@davidturner9827 6 күн бұрын
OOP is upside-down. Types are generalizations of objects, objects aren’t realizations of types.
@michaelutech4786
@michaelutech4786 16 күн бұрын
I remember having seen this in C# years ago, just not with ReadOnlyCollection, so this is not the only violation. This is actually sad, considering that in many regards, C# and .NET is designed very well (and I say that as someone who is not particular happy with the MS ecosystem). Even sadder, I believe I know exactly how this happened. It's a result of two attitudes. One is to not correct mistakes because corrections break existing code. The other is to get things done, also called the 80/20 principle or management making design decisions. The fact that this happened at such a fundamental level as the base data structure abstractions however is shameful.
@sebastianszafran5221
@sebastianszafran5221 13 күн бұрын
Brilliant video, I love it all! This plot twist near the end made me smile. However, I feel like it's missing the explanation of Microsoft's decision about this move. As you said, there are incredible intelligent people working on .NET design, so that I am sure there gotta be a good reason for that
@dmmgualb
@dmmgualb 29 күн бұрын
Totally true. This happens not only with base classes/interfaces, but I have many times encountered such dead-ends in my own code when programming, and the solution is like that one (runtime and ugly). I really would like to see how to fix that.
@tibrec8
@tibrec8 Ай бұрын
This also founded on dart language by google . Theres List Type called : UnmodifiedList ... and if u call Add item on it it throws an exception same as .Net and i know it violating LSV Principal....but i also think dart is a new language why they make it like this
@jorgeromero4680
@jorgeromero4680 Ай бұрын
i really like this video about these horrible decisions and the wise consideration to use types.
@leerothman2715
@leerothman2715 10 күн бұрын
Love it. I am now changing my workshop session on LSP to include this. Basically the way that C# has got round it is by a hack and use and a boolean to the ICollection contract. If you need to check the result of this first then does this go against ‘tell don’t ask’? Not a SOLID principle obviously but a commonly used rule.
@pix3ldust360
@pix3ldust360 29 күн бұрын
Your explanation was engaging and thought-provoking. Made me wonder about the relationship between number of layers of abstraction and probability of violating the Liskov Substitution Principle. For "real-world" solutions of sufficiently complex problems, is this curve likely exponential, linear, or ...?
@logiclrd
@logiclrd 11 күн бұрын
I think they wanted the "common type" to be something that developers (their own developers) could use without thinking. What they should have done is IEnumerable
@Asdayasman
@Asdayasman 3 күн бұрын
What an awful solution - simply don't inherit in interfaces and the problem evaporates. Your idea leads to combinatorial explosion.
@logiclrd
@logiclrd 3 күн бұрын
@@Asdayasman I don't think it does.
22 күн бұрын
That’s crazy. I would also argue that we have an Interface segregation problem here. And yes, maybe technically it’s not a LSP violation, but it’s still bad code.
@sxs512
@sxs512 13 күн бұрын
Ideally you'd want to separate all those functionalities into separate interfaces and have collections implement the ones that make sense. This entire hierarchy is very much a complete mess caused by maintaining backwards compatibility and some language limitations.
@sepiaflux123
@sepiaflux123 13 күн бұрын
Great Video
@MaxwellHay
@MaxwellHay Ай бұрын
When it comes to principles like SOLID, you need to fully understand it and be pragmatic rather than just following it blindly
@ChristopherOkhravi
@ChristopherOkhravi Ай бұрын
Agreed. Except for LSP which I consider to be more like a hard rule. Violating LSP leads to enormously confusing code. The other principles however I completely agree with you are up for debate and you can make pragmatic decisions as to whether or not to care about them in a specific case. But LSP is a different story. It is very clearly defined and it is very clear what is a violation and violating it leads to very clear problems 😊 Thank you for watching and for sharing your thoughts 😊🙏
@user-dc9zo7ek5j
@user-dc9zo7ek5j 14 күн бұрын
Christopher, awesome presentation, with the gestures you remind me a little bit of Morshu :) I want to ask a question because even chat bots confure this one. Is there a circular reference between string and object's ToString? String inherits from object, but object cannot be compiled without string. What do you think?
@user-dc9zo7ek5j
@user-dc9zo7ek5j 14 күн бұрын
Regarding the issue in the video, I think that F# solved this issue and applied a much more pragmatic definition of interfaces. There wasn't a need for interfaces, rather the type must have a method that matches the one that is called in order to compile, without the need of interfaces, making implementations very specific and at the same time, very generic, but I might be wrong, haven't checked.
@xyyx1001
@xyyx1001 12 күн бұрын
I support your cause. Smelly code, oily tuna design, bad Microsoft, bad! Okay, over the top but eye opening video on how to paint yourself into a corner and everyone is susceptible.
@NoAkcess
@NoAkcess Ай бұрын
So could the developer toggle ICollection.readonly to true or false dynamically so at times the collection is readonly? That would explain the exception at runtime.
@louisfrancisco2171
@louisfrancisco2171 18 күн бұрын
IsReadOnly is usually a read-only property. ReadOnlyCollection implementation always returns true. List implementation always returns false. A Collection, when instantiated with a list parameter, just returns the IsReadOnly value of that list. But you could implement it as read-write in your own class if you need to.
@reecedeyoung6595
@reecedeyoung6595 Ай бұрын
When I hear LSP I think language server protocol
@davidmartensson273
@davidmartensson273 16 күн бұрын
I agree, they should have added ImmutableCollection between IEnumerable and ICollection and then add an IReadOnlyList, that would have created a clean hierarchy.
@jonasbarka
@jonasbarka 2 күн бұрын
But then we got the plot twist of ReadOnlyCollection not being immutable. So it should be IReadOnlyCollection. Or just skip ReadOnly for immutable classes.
@sarvarthmonga5764
@sarvarthmonga5764 Ай бұрын
Very nice
@verfran
@verfran Ай бұрын
Excellent. Sometimes I feel so stupid making this kind of mistakes. Now I realize, I shouldn't be too hard on me :)
@ChristopherOkhravi
@ChristopherOkhravi Ай бұрын
I feel the same way 😊
@DaoBeat
@DaoBeat Ай бұрын
Hello my friend and thank you for your new video. It’s very interesting. Would love to hear something interesting about IQueryable.
@o_corisco
@o_corisco 24 күн бұрын
this could be an interesting case for type-families (ts ternary type, or rust traits). In fact, typescript has a utility type that does exactly that. i don't think it will be very long until c# gets functions at the type level.
@Asdayasman
@Asdayasman 3 күн бұрын
You didn't suggest a fix. Inheritance among interfaces appears to be bad design. When I have something that implements IList, all I really care about is the extra stuff it adds on top of its parent class, so it shouldn't have a parent class. Something that today implements IList, should tomorrow implement IList, ICollection, and IEnumerable. If the programmer needs to add something, they call for an ICollection. If they need to index, they call for an IList. If the programmer requires something that is both indexable and add-to-able, they should define their own combination of those types.
@ehsnils
@ehsnils 19 күн бұрын
At first glance I'd like to turn the IEnumerable, ICollection and IList upside down from what you did draw. Mostly because I see the IEnumerable as the root and that it then grows upward. Arrow directions can also be confusing - is the arrows the way the functionality evolves or the way the drill-down occurs. It comes down to the way you think, and it's easy to get locked into one pattern (information flow for example) and if someone else uses a different pattern then it takes time to adapt. At least you did set a baseline in the first 2 minutes. As for the inheritance issue I'd like to change so that the indexing that IList provides should be provided by IEnumerable and the IReadOnlyCollection should be between IEnumerable and ICollection.
@Max-zn7md
@Max-zn7md 17 күн бұрын
Hi chris nice video, I have a question that might be a bit off with the topic of this video, the thing is that i started to read a book called "Dependency Injection: Principles, Practices and Patterns" in wich the author explains the different techniques we can use in order to inject properties into our clases (Constructor injection, Method injection and Property injection), he also explained some anti patterns related to dependency injection (Control freak, service locator, ambient context and constrained constructor), all off these stuff its explained on the chapter 4, 5 and 6 and i think you could create a great video explaining thoso topics
@loam
@loam Ай бұрын
I saw one example of LSP violation myself in .Net source code (when of the methods of base class was not appropriate for the subclass and it was just throwing exception)
@Sproeikoei
@Sproeikoei Ай бұрын
Thank you I really enjoyed the video, especially the inreractive parts! I guess how I would try to solve it: we would want to introduce an iindexer interface and let IList implement that, then also let the ReadyOnlyCollection implement that interface to "solve" this? (With the information that is used in the video)
@drcl7429
@drcl7429 29 күн бұрын
I think you were right first time. I don't know why they made its return value to be void, could have just returned 0 or maybe -1 on add() then. At least Java uses a boolean.
@tesilab994
@tesilab994 18 күн бұрын
C++ has the “feature” of private inheritance where you can steal the implementation without promising to be a subtype. Also a lot of this mess is from mutability overload.
@istvanstefan9315
@istvanstefan9315 Ай бұрын
i don't really get the point of creating a read-only version of any type. If you want to make an instance of a type read-only you could use the const keyword and mark the methods which don't change the state of the object also with const. Or is the const keyword not available in C# (I'm coming from C++ world)?
@CtrlGame
@CtrlGame 22 күн бұрын
c++ has a great way of dealing with readonly. they thought really well the const keyword for methods
@louisfrancisco2171
@louisfrancisco2171 18 күн бұрын
In C#, you can mark the methods of a struct with the readonly keyword.
@Tsunami14
@Tsunami14 2 күн бұрын
My perspective is that it helps to reduce unintended side effects. Say I created function ProcessData(IList list). Since the list is passed by reference, there's nothing stopping me from modifying the list in ways that someone calling the function might not expect. By contrast, if I have a ProcessData(IReadOnlyList list), then that communicates a guarantee (ignoring reflection / recasts) to the caller that the list will not be modified. Side effects can be VERY tricky to debug and hunt down, so imho, it's generally a good idea to reduce those opportunities as much as possible.
@franciscosilva7302
@franciscosilva7302 22 күн бұрын
Why isReadOnly means no LSP violation?
@drapala97
@drapala97 Ай бұрын
Any plans to continue the object oriented lectures?
@ChristopherOkhravi
@ChristopherOkhravi Ай бұрын
My sincere apologies but the answer is unfortunately no. I recorded everything but it didn't turn out as good as I wanted it to. I've got a few things in the works however so it is possible that I might redo it from scratch but that's far out into the future. Again, my sincere apologies.
@drapala97
@drapala97 Ай бұрын
@@ChristopherOkhravi no need to apologize, your content is awesome
@numeritos1799
@numeritos1799 Ай бұрын
I mean why/when would you require a read-only collection anyway? If you're going to only read through a collection, you don't really care if it's read-only or not, and limiting it to only read-only collections through the type-system would do more harm than good. I think it's just a hard problem to solve, if not impossible, would love to hear a better solution though if anyone has it. Just as a side note, Java solves this in a similar way: UnmodifiableCollection implements Collection.
@silberwolfSR71
@silberwolfSR71 Ай бұрын
One common use case would be to communicate and enforce a contract: my library function takes a collection, does some computation using its elements and returns some result to you. In the contract of this function, I promise not to alter any collection you pass me. This is important, because you can now pass me a collection without having to worry (and verify) whether it has changed after I'm done with it. If we have interfaces defining read-only collections, I can both document and enforce this contract succinctly and reliably in one place. Conversely, as it currently stands in C# and Java, you basically have to both read the (prose) documentation of my function to find out this part of the contract and trust my library to actually adhere to it. This makes the contract at the same time weaker _and_ harder to discover, neither of which is a desirable quality in this context. In short, I may not care much if a collection you pass me also supports modification if I only need to read it, but you should care whether I can modify a collection you pass me or not. I'm curious what you imagine the harm done to be of defining a ReadableCollection interface that is extended by a MutableCollection interface which simply adds the add and remove methods. If my function must somehow mutate your collection in order to fulfill its goals, it can define a parameter of type MutableCollection, which also implicitly communicates to you that I intend to alter your collection. If you already have a MutableCollection but my function only requires a ReadableCollection (and defines its parameter accordingly), you can simply pass me your mutable collection with the reassurance that I still can't modify it, without any additional effort on your part. As to the hard problem to solve, maybe you can elaborate on what exactly that problem is?
@adambickford8720
@adambickford8720 Ай бұрын
Thats how the entirety of functional programming works and increasingly considered the norm. Don't mutate your arguments.
@numeritos1799
@numeritos1799 Ай бұрын
@@silberwolfSR71 Don't you see the problem with what you're saying? "...defining a ReadableCollection interface that is extended by a MutableCollection interface". If so, the LSP is "violated" once again, and in a WAY worse way, IMO.
@numeritos1799
@numeritos1799 Ай бұрын
@@adambickford8720 Okay but C# isn't a functional language? The LSP doesn't refer to functional programming either. I don't really see your point. EDIT: just to clarify, I see the purpose of immutable collections, of course. But in a hierarchy structure like it's defined in C# (IEnumerable, ICollection, IList, etc), I don't see the point of having an LSP-compliant read-only collection.
@adambickford8720
@adambickford8720 Ай бұрын
@@numeritos1799 What do you think linq is? Get educated before coping an attitude, mmkay?
@codahighland
@codahighland 4 күн бұрын
And this is why C++ has `const`. You don't need to have two different types for this.
@McZsh
@McZsh 24 күн бұрын
Also, arrays are collections that cannot be added to, but can be changed by index. Readonly collections cannot be changed by index. The implementations of ICollection and IList are basically flipped. It would have been better concentrate the mutability methods and properties in the most top level type. IReadOnlyCollections stems from this historic mistake, with ReadOnlyCollection being a simple wrapper around every other collection type to make it work. You wouldn't use it in any declaration.
@thewelder3538
@thewelder3538 23 күн бұрын
I love your delivery and presentation; quite refreshing. Let's face it though, LSP is just a load of bollocks anyway. If you're writing code and giving a crap about stuff like LSP, the chances are you're writing crappy code.
@ChristopherOkhravi
@ChristopherOkhravi 22 күн бұрын
Thank you for your perspective. Would you care to elaborate what you mean? If you are violating LSP then you are essentially writing type unsafe code. So LSP is not really on the same “level” as other principles like say SRP or OCP. Imho LSP is much more important and much more clear. I would also hold that LSP is “discovered” more than “invented”. In the same way that mathematics is “discovered” rather than “invented”. But regarding most other principles I see what you mean 😊😊 Thank you again for sharing your perspective 😊🙏
@thewelder3538
@thewelder3538 22 күн бұрын
@@ChristopherOkhravi I'm more of a C++ coder than a C# one, I just happen to have ended up coding a large amount of C# recently. Now, I think of a list as being node based, as opposed to a vector which is more like an array. It's kind of weird that something contiguous in C# like List is called a list. Now I don't care what interfaces it implements, I just need to store a contiguous set of bytes. Nor do I care about interfaces at all when the concrete class will do just fine. Sure, if you have nothing better to think about than all these collections have the same contract with an interface, fine, but it's still just about storing some data. I've lost so much time removing things declared as IEnumerable because I needed something way more useful than an interface just defining that my collection is enumerable. Most of the things I use especially, have very defined sizes and having these abstract interfaces, just makes things more of a pain in the arse than it should be. Moreover, being able to substitute one collection for another just because they inherit from the same interface is all just a bit of nonsense in real-world terms. Also std::map which the C# equivalent is Dictionary is sorted by default. The C# equivalent of map must be weirdly implemented not to exhibit this behaviour. We have unordered_map for a key/value container where order is not maintained.
@__christopher__
@__christopher__ 14 күн бұрын
If you violate LSP, you are effectively lying about your class. You are promising "this can be used as a Whatever" when it actually can't be used that way.
@Akronymus_
@Akronymus_ 13 күн бұрын
Inheritance/interfaces are fantastic, the only big problem, for me, is the diamond problem. For example, what if you want to support passing IList to a function that expects a IReadOnlyCollection, because you want to ensure you don't to change the collection in the function that uses it. Under the current hirachy you simply can't do that, unless you go to just an IEnumerable. How would you solve that?
@TheFrewah
@TheFrewah 11 күн бұрын
Usually people end up with spaghetti code when they get things wrong. I do remember a former colleague that always wanted to use everything he knew about object oriented programming and his code was horrible. You could easily remove 50%
@Tsunami14
@Tsunami14 2 күн бұрын
Speaking from memory (too lazy to test), but I think you can pass the IList straight through without any issues, and it would automatically get cast to the IReadOnlyCollection expected by the function. (IList implements IReadOnlyCollection, so the cast is valid)
@one.pouria786
@one.pouria786 27 күн бұрын
Maybe if we had conditional types like typescript in C#, programmers would be able to deal with it more effectively
@todortotev5399
@todortotev5399 6 күн бұрын
I suffered the entirety of the 18 minutes wandering, why this is not a 30 seconds Shorts, because that's the length of the useable content.
@todortotev5399
@todortotev5399 6 күн бұрын
Also, ffs, LSV was not violated, it's just that the basic interface behaves weirdly (but in a well-documented way) and the class that implemented it implemented it fully. So essentially, the video title is a lie, and the the entire video is just garbage.
@ChristopherOkhravi
@ChristopherOkhravi 5 күн бұрын
Thank you very much for the feedback 😊🙏 and I'm sorry to have made you angry. Many are not familiar with all the details which is why we are taking it so slowly. Imho I still belive that we should read this as a violation of LSP. As I say in the video I of course agree that it is not technically a violation. But still, it seems to me that most of us would agree that there is an obviously right way to structure this hierarchy and that the way they chose to structure it is NOT the right way. Moving errors from compile-time to run-time is NOT a sensible thing to do in a statically typed language. And as soon as we disregard the IsReadOnly property and the run-time exception (which should NOT be there because this is a statically typed language and this problem is entirely solvable without them) this becomes a violation of LSP. Thanks for watching and for commenting! Just a headsup: I will keep posting long-form content so please consider yourself warned 😊
@Wildstraw
@Wildstraw Ай бұрын
what is his name?
@ErezAvidan1
@ErezAvidan1 Ай бұрын
the whole problem starts and ends with inheritance, this time is not inheritance between classes but between interfaces
@ChristopherOkhravi
@ChristopherOkhravi Ай бұрын
The issue is not inheritance but subtyping. LSP applies as soon as there is subtyping. Thank you for watching and for sharing your thoughts 😊🙏
@friedrichdergroe9664
@friedrichdergroe9664 28 күн бұрын
This could be resolved easily with Haskell's static typing. Pretty trivially, actually, so that violators fail at compile time. an isReadOnly() function is a bad idea. The read-only quality should be embodied by the typing directly.
@mehtazsazid9398
@mehtazsazid9398 Ай бұрын
Doesn't it break ISP? Read only collection is forced to implement add and write method.
@user-yd9xy3rb4x
@user-yd9xy3rb4x Ай бұрын
Cool as usual. I wonder how one interface can inherit from another 😊
@ChristopherOkhravi
@ChristopherOkhravi Ай бұрын
The signatures are inherited. The subtype interface contains all signatures of the parent. Thanks for watching 😊😊
@davidwilliss5555
@davidwilliss5555 29 күн бұрын
It would have made more sense for ICollection to inherit IReadOnlyCollection
@ahmedalirefaey3219
@ahmedalirefaey3219 Ай бұрын
hold second i think Microsoft make this for business perspective to check in runtime if it read only collections or not (but in compile time will pass it ) it suppose to handle this runtime in derived business class
@fulconandroadcone9488
@fulconandroadcone9488 Ай бұрын
Did I miss something or someone actually made read only collection and then implemented add / remove methods with exceptions?
@vytah
@vytah Ай бұрын
Yes. System.Collections.ObjectModel.ReadOnlyCollection implements IList and all modifying methods throw unconditionally.
@fulconandroadcone9488
@fulconandroadcone9488 Ай бұрын
@@vytah I think I'll stick with JavaScript for the time being.
@Aaron-wg6ft
@Aaron-wg6ft 15 күн бұрын
If ICollection has a read_only property, then what's the point of IReadOnlyCollection? And yes, it's a violation.
@Junior7setti
@Junior7setti Ай бұрын
Dont know the whole interface and methods there. But I think they could have ICollection be a sub type of IReadOnlyCollection instead, then from there fork between IList and IReadOnlyList which then is implemented by ReadOnlyCollection. I believe they had a very good reason to do the way they did instead. It is hard to please everyone when developing a large framework or library.
@ChristopherOkhravi
@ChristopherOkhravi Ай бұрын
I suppose we should please Barbara Liskov first? 😁 Thank you for sharing your thoughts. I would not be comfortable with having a mutable collection be a subtype of an immutable collection. Seems like this would lead to violating LSP by violating invariants in the supertype. But I may be mistaken. Thank you very much for watching and sharing your thoughts 😊🙏
@Robert-yw5ms
@Robert-yw5ms Ай бұрын
@@ChristopherOkhravi I can imagine a method that accepts a ReadOnlyCollection, and uses it under the assumption that the collection will never be mutated. But some other method is running on another thread with the same collection, but this other method knows the Collection is mutable and so mutates it, causing issues in the first method. Would you say this demonstrates why such a subtype would violate LSP?
@arjix8738
@arjix8738 Ай бұрын
@@ChristopherOkhravi nah, Barbara Liskov can go cry about it jokes aside, it probably was made this way to not break existing code
@Scorbutics
@Scorbutics Ай бұрын
@@ChristopherOkhravi Sure, but you could rename it as "ReadableCollection", which would make more sense in this hierarchy location, because you remove the "only" part of the ReadonlyCollection
@barneylaurance1865
@barneylaurance1865 16 күн бұрын
@@Scorbutics You'd probably to rename it to just Collection then. Presumably all collections are readable.
@CtrlGame
@CtrlGame 22 күн бұрын
If it where me, I would create a method to convert the ICollection to IReadOnlyCollection and vice versa without copying the items (In a c++ way with move semantics). The fact that the class is a child of the IList feels wrong to me. Just why? But, I still like c#. The interfaces are there. You can make your own IReadOnlyCollection and ICollection if you want to fix this by yourself.
@Miszkaaaaa
@Miszkaaaaa 29 күн бұрын
I was repeating "Yes!" almost every 4 seconds after 15:37
@AbhinavGunwant
@AbhinavGunwant 27 күн бұрын
Who else is dumb like me and saw the thumbnail and thought "Languagae Server Protocol"?
@chudchadanstud
@chudchadanstud Ай бұрын
Logically ICollection should only contain immutable methods and properties. If you need mutation just upcast or get the correct interface like IList. Even better there should be an interface call IWriteableCollection or IMutableCollection I am also not a big fan of the Add and Remove methods in ICollection. You can't just add or remove in a static array. An Array is a collection.
Liskov Substitution Principle
20:16
Christopher Okhravi
Рет қаралды 10 М.
The Only Time You Should Use Polymorphism
13:55
Christopher Okhravi
Рет қаралды 87 М.
I CAN’T BELIEVE I LOST 😱
00:46
Topper Guild
Рет қаралды 36 МЛН
Мы никогда не были так напуганы!
00:15
Аришнев
Рет қаралды 1,5 МЛН
Khóa ly biệt
01:00
Đào Nguyễn Ánh - Hữu Hưng
Рет қаралды 19 МЛН
This Is Why Managers Don't Trust Programmers...
28:04
Thriving Technologist
Рет қаралды 200 М.
Swagger is Going Away in .NET 9!
10:48
Nick Chapsas
Рет қаралды 87 М.
Liskov: The Liskov Substitution Principle
4:23
Turing Awardee Clips
Рет қаралды 19 М.
Covariance and Contravariance
13:31
Christopher Okhravi
Рет қаралды 11 М.
Always Use Interfaces
8:08
Christopher Okhravi
Рет қаралды 44 М.
5 Design Patterns That Are ACTUALLY Used By Developers
9:27
Alex Hyett
Рет қаралды 192 М.
Liskov's Substitution Principle | SOLID Design Principles (ep 1 part 1)
16:08
Christopher Okhravi
Рет қаралды 157 М.
That's NOT How Async And Await Works in .NET!
12:25
Codewrinkles
Рет қаралды 16 М.
Harder Than It Seems? 5 Minute Timer in C++
20:10
The Cherno
Рет қаралды 146 М.
The 3 Laws of Writing Readable Code
5:28
Kantan Coding
Рет қаралды 284 М.
I CAN’T BELIEVE I LOST 😱
00:46
Topper Guild
Рет қаралды 36 МЛН