When Microsoft Violated Liskov Substitution Principle in .NET

แชร์
ฝัง
  • เผยแพร่เมื่อ 27 ก.ย. 2024

ความคิดเห็น • 319

  • @demarcorr
    @demarcorr 4 หลายเดือนก่อน +64

    I *promise* you, cross my heart, swear to god, or smite me now, I violate every single SOLID principle, every single day, without fail.

  • @amerbashoeb2106
    @amerbashoeb2106 4 หลายเดือนก่อน +29

    I just cant you thank you enough. There is no one on TH-cam who teaches like you do. Thank you brother.

  • @krozaine
    @krozaine 4 หลายเดือนก่อน +56

    What a roller coaster ride in the explanation, especially with the entry of isReadOnly. Super awesome take on the issue and explanation!

    • @ChristopherOkhravi
      @ChristopherOkhravi  4 หลายเดือนก่อน +1

      Glad you enjoyed it! 😊 Thanks for watching 🙏😊

  • @francisadediran6311
    @francisadediran6311 4 หลายเดือนก่อน +89

    "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 4 หลายเดือนก่อน +10

      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 4 หลายเดือนก่อน +2

      @@drcl7429 Not being sarcastic, just highlighting a very good point which i have forgotten

    • @ChristopherOkhravi
      @ChristopherOkhravi  4 หลายเดือนก่อน +9

      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 3 หลายเดือนก่อน +1

      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 3 หลายเดือนก่อน

      ​​@@_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.

  • @BeatsByYari
    @BeatsByYari 4 หลายเดือนก่อน +36

    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 4 หลายเดือนก่อน

      So does IsReadOnly return true for Array then?

    • @modernkennnern
      @modernkennnern 3 หลายเดือนก่อน

      It only throws if it's full, but yes. It's annoying

  • @renatogolia211
    @renatogolia211 4 หลายเดือนก่อน +7

    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.

  • @vincentjacquet2927
    @vincentjacquet2927 4 หลายเดือนก่อน +13

    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 3 หลายเดือนก่อน

      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 3 หลายเดือนก่อน

      @@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 3 หลายเดือนก่อน

      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.

  • @vishalrajage-c7u
    @vishalrajage-c7u 4 หลายเดือนก่อน +8

    What a clear explanation of complex Liskov violation on more complicated hierarchy of Collections... Hats off!.!! 😊😅

  • @quentinparis1113
    @quentinparis1113 4 หลายเดือนก่อน +6

    @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  4 หลายเดือนก่อน +2

      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 😊😊

  • @ProjSHiNKiROU
    @ProjSHiNKiROU 3 หลายเดือนก่อน +4

    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 หลายเดือนก่อน +1

      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?

  • @dawid_dahl
    @dawid_dahl 4 หลายเดือนก่อน +5

    I will send this video to anyone who’d like to learn the LSP! 👏🏻

  • @michaelwikstrom
    @michaelwikstrom 3 หลายเดือนก่อน +2

    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#

  • @Scorbutics
    @Scorbutics 4 หลายเดือนก่อน +9

    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 4 หลายเดือนก่อน +1

      MutableCollection : CollectionMutator, ReadOnlyCollection

  • @adambickford8720
    @adambickford8720 4 หลายเดือนก่อน +138

    Before cheating off java's homework, make sure it's right

    • @ChristopherOkhravi
      @ChristopherOkhravi  4 หลายเดือนก่อน +14

      Underrated comment 😆

    • @sergtachini
      @sergtachini 4 หลายเดือนก่อน

      Java has the same, Collections.unmodifiableList or List.of

    • @redcrafterlppa303
      @redcrafterlppa303 4 หลายเดือนก่อน +18

      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 4 หลายเดือนก่อน +6

      Yeap, they went ass backwards, it should have been ICollection and IMutableCollection.

    • @andywong3095
      @andywong3095 4 หลายเดือนก่อน +2

      J-things expert, talking about c# and Dot-things.

  • @jackwesleymoreira
    @jackwesleymoreira 4 หลายเดือนก่อน +13

    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  4 หลายเดือนก่อน +1

      Thank you for the feedback. Much appreciated. And thank you for watching 😊🙏

    • @arjix8738
      @arjix8738 4 หลายเดือนก่อน +1

      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 3 หลายเดือนก่อน

      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.

  • @Misteribel
    @Misteribel 4 หลายเดือนก่อน +9

    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 3 หลายเดือนก่อน +6

      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.

  • @IroAppe
    @IroAppe 3 หลายเดือนก่อน +2

    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...

  • @tibrec8
    @tibrec8 4 หลายเดือนก่อน +3

    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

  • @AndreyRogozhnikov
    @AndreyRogozhnikov 3 หลายเดือนก่อน +1

    Wow! Such a clear and logical delivery!

    • @ChristopherOkhravi
      @ChristopherOkhravi  3 หลายเดือนก่อน

      🙏 Thank you for watching 😊🙏

  • @sagarbhosale3337
    @sagarbhosale3337 4 หลายเดือนก่อน +1

    Very well explained. Requesting video on Liskov Substitution VS Interface segregation principle.

  • @fourZerglings
    @fourZerglings 3 หลายเดือนก่อน

    There's a simpler example: arrays in .NET implement IList without support for Add or Remove

  • @AerysBat
    @AerysBat 3 หลายเดือนก่อน

    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.

  • @CodingTutorialsAreGo
    @CodingTutorialsAreGo 3 หลายเดือนก่อน +1

    I share your pain, though an even more fundamental violation is:
    IList list = new int[] { 1, 2, 3, 4, 5 };
    list.Add(27);

  • @vchap01
    @vchap01 4 หลายเดือนก่อน +1

    .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.

  • @lawrencejob
    @lawrencejob 4 หลายเดือนก่อน

    Thanks for articulating this. It’s been frustrating me for years!

  • @orterves
    @orterves 3 หลายเดือนก่อน +1

    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.

  • @sebastianszafran5221
    @sebastianszafran5221 3 หลายเดือนก่อน

    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

  • @qj0n
    @qj0n 3 หลายเดือนก่อน

    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

  • @ran-j
    @ran-j 3 หลายเดือนก่อน

    This video was simply fantastic, great explanation about LSP

  • @istvanstefan9315
    @istvanstefan9315 4 หลายเดือนก่อน +1

    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 3 หลายเดือนก่อน

      c++ has a great way of dealing with readonly. they thought really well the const keyword for methods

    • @louisfrancisco2171
      @louisfrancisco2171 3 หลายเดือนก่อน

      In C#, you can mark the methods of a struct with the readonly keyword.

    • @Tsunami14
      @Tsunami14 3 หลายเดือนก่อน

      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.

  • @leerothman2715
    @leerothman2715 3 หลายเดือนก่อน

    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.

    • @ChristopherOkhravi
      @ChristopherOkhravi  2 หลายเดือนก่อน +1

      Thank you for sharing this! 🙏😊

  • @logiclrd
    @logiclrd 3 หลายเดือนก่อน +1

    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.

  • @BlindVirtuoso
    @BlindVirtuoso 4 หลายเดือนก่อน

    Chris, you are fantastic. Highly appreciate!

  • @loam
    @loam 4 หลายเดือนก่อน

    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)

  • @JohnDoe4321
    @JohnDoe4321 3 หลายเดือนก่อน +3

    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 3 หลายเดือนก่อน

      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.)

  • @franciscosilva7302
    @franciscosilva7302 3 หลายเดือนก่อน

    Why isReadOnly means no LSP violation?

  • @Nobody1707
    @Nobody1707 3 หลายเดือนก่อน

    Coming from Swift, I'm surprised by that interface hierarchy. The equivalent protocol hierarchy in Swift is Sequence

    • @jvesoft
      @jvesoft 3 หลายเดือนก่อน

      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. :)

  • @o_corisco
    @o_corisco 3 หลายเดือนก่อน

    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.

  • @reecedeyoung6595
    @reecedeyoung6595 4 หลายเดือนก่อน +1

    When I hear LSP I think language server protocol

  • @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.

  • @Sproeikoei
    @Sproeikoei 4 หลายเดือนก่อน

    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)

  • @Aaron-wg6ft
    @Aaron-wg6ft 3 หลายเดือนก่อน

    If ICollection has a read_only property, then what's the point of IReadOnlyCollection? And yes, it's a violation.

  • @samyakshah806
    @samyakshah806 4 หลายเดือนก่อน

    Hey, just wanted to let you know that the link on recommended books, placed on your website, is not working

  • @Flynnor
    @Flynnor 3 หลายเดือนก่อน

    Great insights. Thank you.

  • @moristar
    @moristar 3 หลายเดือนก่อน

    It's like the first thing that gets violated in OOP and probably the least important TBH

  • @sxs512
    @sxs512 3 หลายเดือนก่อน

    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.

  • @perian1983
    @perian1983 4 หลายเดือนก่อน

    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?

  • @MaxwellHay
    @MaxwellHay 4 หลายเดือนก่อน +1

    When it comes to principles like SOLID, you need to fully understand it and be pragmatic rather than just following it blindly

    • @ChristopherOkhravi
      @ChristopherOkhravi  4 หลายเดือนก่อน +1

      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 😊🙏

  • @verfran
    @verfran 4 หลายเดือนก่อน

    Excellent. Sometimes I feel so stupid making this kind of mistakes. Now I realize, I shouldn't be too hard on me :)

  • @jorgeromero4680
    @jorgeromero4680 4 หลายเดือนก่อน

    i really like this video about these horrible decisions and the wise consideration to use types.

  • @mehtazsazid9398
    @mehtazsazid9398 4 หลายเดือนก่อน

    Doesn't it break ISP?
    Read only collection is forced to implement add and write method.

  • @friedrichdergroe9664
    @friedrichdergroe9664 4 หลายเดือนก่อน

    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.

  • @numeritos1799
    @numeritos1799 4 หลายเดือนก่อน

    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 4 หลายเดือนก่อน +1

      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 4 หลายเดือนก่อน +1

      Thats how the entirety of functional programming works and increasingly considered the norm. Don't mutate your arguments.

    • @numeritos1799
      @numeritos1799 4 หลายเดือนก่อน

      @@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 4 หลายเดือนก่อน +1

      @@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 4 หลายเดือนก่อน

      @@numeritos1799 What do you think linq is?
      Get educated before coping an attitude, mmkay?

  • @tesilab994
    @tesilab994 3 หลายเดือนก่อน

    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.

  • @one.pouria786
    @one.pouria786 4 หลายเดือนก่อน

    Maybe if we had conditional types like typescript in C#, programmers would be able to deal with it more effectively

  • @rastersoft
    @rastersoft 3 หลายเดือนก่อน

    Mmm... so... the right way of doing that would have been IEnumerable

    • @barneylaurance1865
      @barneylaurance1865 3 หลายเดือนก่อน

      No, list can't inherit from ReadOnlyList - that would violate the history constraint. A readOnlyCollection presumably should return the same data every time it's read. A subtype that doesn't behave like that violates the LSP. You could have MutableCollection inheriting from Collection, and ReadOnlyCollection as a sibling of MutableCollection also inheriting from Collection.

  • @professorfontanez
    @professorfontanez หลายเดือนก่อน

    Seems to me, and call me crazy, that if ICollection has a property that can make it a "read only" collection then IReadOnlyCollection is an unnecessary interface.

  •  3 หลายเดือนก่อน

    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.

  • @paviad
    @paviad 4 หลายเดือนก่อน

    Why is ReadOnlyCollection implementing IReadOnlyCollection and not simply IEnumerable? Who else implements IReadOnlyCollection?

    • @louisfrancisco2171
      @louisfrancisco2171 3 หลายเดือนก่อน

      Apparently, over 70 classes implement it.

    • @paviad
      @paviad 3 หลายเดือนก่อน

      @@louisfrancisco2171 just wondering, what is the point of this interface? How can it guarantee the read only feature? Only a sealed class can guarantee something like this. The type system absolutely has no role here.

    • @louisfrancisco2171
      @louisfrancisco2171 3 หลายเดือนก่อน

      @@paviad The point of it not being a sealed class is so you can implement your own IReadOnlyCollection. No interface guarantees anything about the behavior of the classes implementing it. You could write a class implementing IDisposable and have its Dispose method allocate resources instead of releasing them.

    • @paviad
      @paviad 3 หลายเดือนก่อน

      @@louisfrancisco2171 that's not how I see it, an IDisposable guarantees the existence of a dispose method, IReadOnlyCollection cannot guarantee the lack of an Add method.

    • @paviad
      @paviad 3 หลายเดือนก่อน

      @@louisfrancisco2171 I don't see it that way, an IDisposable guarantees the existence of the Dispose method, an IReadOnlyCollection cannot guarantee the lack of the Add or Clear methods (or an infinite number of other methods)

  • @YuryPastushenko
    @YuryPastushenko 4 หลายเดือนก่อน

    I just don't get why IList should be inherited from ICollection. Indexing shouldn't have anything with addin and removing anything. For example Array has indexing but doesn't support adding and removing. IMHO IList and ICollection should both inherit from IEnumerable.

  • @AbhinavGunwant
    @AbhinavGunwant 4 หลายเดือนก่อน +1

    Who else is dumb like me and saw the thumbnail and thought "Languagae Server Protocol"?

  • @ShivamKendre-fc3su
    @ShivamKendre-fc3su 3 หลายเดือนก่อน

    What a great video!!

  • @alanmaia8880
    @alanmaia8880 4 หลายเดือนก่อน +1

    Playing devils advocate here, they kinda have the type restriction via the interfaces which would be the most wise way of using these types.
    Without looking at the code is hard to say, but maybe ReadOnlyCollection just reuses the code of some other class but setting ReadOnly to true.
    Its still a weird design decision but I wouldn’t say it’s too bad given we have the interfaces properly done.

    • @johndenver8907
      @johndenver8907 4 หลายเดือนก่อน

      If someone uses C# daily and has used an IReadOnlyCollection quite often I bet they've also never had a single ReadOnlyCollection. As in maybe you could new it up, but then adding values to it would just mean it's not actually read only so it's not meant to be used that way. it's an implementation detail that would be part of the guts of the framework. Yeah, it's weird, but I'm sure it's not the only thing you can find, and it truthfully has no negative affect at all.

    • @louisfrancisco2171
      @louisfrancisco2171 3 หลายเดือนก่อน

      @@johndenver8907 You're supposed to pass the values to its constructor. You don't add anything to it afterwards.

    • @johndenver8907
      @johndenver8907 3 หลายเดือนก่อน

      @@louisfrancisco2171 Oh man. Yes I assume that would be the case. But you would of course be using an interface and if you happen to have a ReadOnlyCollection I hope that you're at least passing it out as an IEnumerable or IReadOnlyCollection. I'm saying that if you program C# professionally you don't use a ReadOnlyCollection except for this strange edge case where you want to make sure that the interfaces you used to express your intent to make it readonly can't be cast to something mutable. I'm aware of the edge case, but we all still just use the interfaces and the ReadOnlyCollection is there for the edge case I spoke about. But thanks for telling me how to new it up. My advice is don't do that.

  • @novelhawk
    @novelhawk 3 หลายเดือนก่อน

    I don't agree.
    I started typing the reason why but it's too long.
    The only problem to me is that ICollection does not implement IReadOnlyCollection and IList does not implement IReadOnlyList

    • @ChristopherOkhravi
      @ChristopherOkhravi  3 หลายเดือนก่อน

      Depending on how you define the read-only interfaces that could follow LSP. But not necessarily imho 😊 I’m specifically thinking of whether you consider the interfaces to have invariants stating that the collection of items may never change. (Feel free to check out my full video on LSP for more on invariants if you have not already: th-cam.com/video/7hXi0N1oWFU/w-d-xo.html). Thank you very much for sharing your perspective 😊🙏

  • @uuuuuu352
    @uuuuuu352 4 หลายเดือนก่อน

    I expected you show at the end of the video how your solution would be.

  • @DaoBeat
    @DaoBeat 4 หลายเดือนก่อน

    Hello my friend and thank you for your new video. It’s very interesting. Would love to hear something interesting about IQueryable.

  • @alexanderkvenvolden4067
    @alexanderkvenvolden4067 3 หลายเดือนก่อน +1

    I'm going to make an IDuck interface with a Quack method and a Penguin class that implements it. Penguins can't quack so that'll be a NotSupportedException. You may THINK this is bad, but it's actually not because I didn't tell you about a "bool CanQuack()" method I put on IDuck that the gullible idiots who use my code should know that you should call first, instead of just ASSUMING that an IDuck can quack. 🙄

    • @Tsunami14
      @Tsunami14 3 หลายเดือนก่อน

      Nailed it!

  • @davidwilliss5555
    @davidwilliss5555 4 หลายเดือนก่อน

    It would have made more sense for ICollection to inherit IReadOnlyCollection

  • @paolomeozzi7119
    @paolomeozzi7119 4 หลายเดือนก่อน

    Great video, Christopher. In this regard, another violation of the LSP in .NET is the Stream abstract class and its derived classes.

  • @Junior7setti
    @Junior7setti 4 หลายเดือนก่อน

    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  4 หลายเดือนก่อน +1

      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 😊🙏

    • @arjix8738
      @arjix8738 4 หลายเดือนก่อน

      @@ChristopherOkhravi nah, Barbara Liskov can go cry about it
      jokes aside, it probably was made this way to not break existing code

    • @Scorbutics
      @Scorbutics 4 หลายเดือนก่อน +1

      @@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 3 หลายเดือนก่อน +1

      @@Scorbutics You'd probably to rename it to just Collection then. Presumably all collections are readable.

    • @__christopher__
      @__christopher__ 3 หลายเดือนก่อน

      @@ChristopherOkhravi Readonly is not the same as immutable. Immutable means it won't ever change. Readonly on the other hand only means *you* cannot change it.
      However I nevertheless agree that it would not make sense to derive a writable collection from a non-writable one. But that's just a matter of naming: Name the thing you cannot write to "Collection" and the thing you can write to as "WritableCollection": Then clearly a writable collection is a collection.

  • @delicious_seabass
    @delicious_seabass 3 หลายเดือนก่อน +2

    Not to bash the video or you yourself. You seem good teacher, to be honest. It's just amazing how much simpler programming is when you realize how none of this actually matters and how stupid and overly complicated OOP makes everything. What's funny to me is that the complaint here boils down to the fact that IsReadOnly is being checked at runtime instead of compile time, but you're using a managed language where literally everything is being JIT compiled and checked at run time.

    • @syriuszb8611
      @syriuszb8611 3 หลายเดือนก่อน +1

      JIT has nothing to do with it. If programmer will get compiler error they have to fix it before they build the program. Not when JIT will finally compile it. You hate something and you don't even know what.

  • @sepiaflux123
    @sepiaflux123 3 หลายเดือนก่อน

    Great Video

  • @georgeblazhev
    @georgeblazhev 4 หลายเดือนก่อน

    Great video!

  • @todortotev5399
    @todortotev5399 3 หลายเดือนก่อน

    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 3 หลายเดือนก่อน

      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  3 หลายเดือนก่อน

      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 😊

  • @codahighland
    @codahighland 3 หลายเดือนก่อน

    And this is why C++ has `const`. You don't need to have two different types for this.

  • @yairlevi8469
    @yairlevi8469 4 หลายเดือนก่อน +8

    Why would they design it in such a way? Every programmer who sees this immediately understands the fallacy here. How come?

    • @jimiscott
      @jimiscott 4 หลายเดือนก่อน +3

      History, cross and backwards compatibility.

    • @ChristopherOkhravi
      @ChristopherOkhravi  4 หลายเดือนก่อน +3

      I too assumed it has something to do with the backwards compatibility. Perhaps something related to non-generic collection types with less type safety. But I have not looked deeper into this 😊 Thank you for watching 😊🙏 (And my apologies for not being able to answer properly)

    • @Tsunami14
      @Tsunami14 4 หลายเดือนก่อน +2

      There was a Microsoft article explaining the design decision when all the IReadOnly's were first added, but I can't seem to find it.

    • @Tsunami14
      @Tsunami14 4 หลายเดือนก่อน +4

      Now i remember!!
      The ReadOnlyCollection class was added in NET 2, but we didn't get the IReadOnly family of interfaces until NET 4.5.
      In the spirit of LSV, it would have been ideal if they also changed the ReadOnlyCollection definition in 4.5 to implement the new IReadOnlyCollection instead of IList, but that could be a breaking change for any existing code.

    • @jimiscott
      @jimiscott 4 หลายเดือนก่อน +1

      @Tsunami14 - Not only that, but they needed to keep source code compatible between .net 1.0/1.1 so people could use the generic versions of the interfaces easily without a whole bunch of source code changes. So what you ended up with is a bunch of non-generic read/write interfaces having generic equivalents. Then the IReadOnlyCollection was added in 4.5, but you couldn't change the inheritance chain since that would break everything.

  • @mohamaddelkhah
    @mohamaddelkhah 4 หลายเดือนก่อน

    I was thinking about growing a mustache, but now I'm wondering would it force me to inevitably become a successful programming TH-camr (regardless of my wishes) or not?

    • @ChristopherOkhravi
      @ChristopherOkhravi  4 หลายเดือนก่อน

      It is also possible you might end up as a finance TH-camr. And the returns are better over there so maybe that would be a good thing 😁

  • @Miszkaaaaa
    @Miszkaaaaa 4 หลายเดือนก่อน

    I was repeating "Yes!" almost every 4 seconds after 15:37

  • @dariofagotto4047
    @dariofagotto4047 3 หลายเดือนก่อน

    Imagine how funny (and probably it is) if ICollection read only getter COULD change during the lifetime of the object, it wouldn't even be safe to check it before add...

    • @louisfrancisco2171
      @louisfrancisco2171 3 หลายเดือนก่อน

      If you make a class implementing ICollection with a read-write IsReadOnly property, then it could change between checking its value and calling Add. You can always implement interfaces whichever way you want, even if it's silly.

  • @labbertubes
    @labbertubes 4 หลายเดือนก่อน

    A hard-core teckie with the persuasiveness of a high-grade lawyer. Please don't go ito politics :D

  • @bariole
    @bariole 4 หลายเดือนก่อน

    [13:16] "If we have good Type hierarchy"....🤥

  • @afterglow5285
    @afterglow5285 4 หลายเดือนก่อน

    Another W for dotnet, sure it "breaks" some principle, but is really that important?, i dont think so. The collections in c# are still waaay more flexible, easy to use than the unholy mess that is the java collections.

  • @no_name4796
    @no_name4796 3 หลายเดือนก่อน +1

    The video thumbnail is misgiuding.
    Honestly if you ask most devs what LSP mean, they will say language server protocol lol

    • @ChristopherOkhravi
      @ChristopherOkhravi  3 หลายเดือนก่อน +1

      Interesting. That abbreviation is too new skool for me 😊 LSP has always been Liskov in my world. Thank you for letting me know 😊

  • @mortenhattesen
    @mortenhattesen 3 หลายเดือนก่อน

    IReadOnly* is a poor naming. It should be called IImmutable*.

  • @Alguem387
    @Alguem387 4 หลายเดือนก่อน

    The Stream class is a hole can of worms itsself

  • @ethanr0x
    @ethanr0x 3 หลายเดือนก่อน

    Welcome to .NET

  • @ddystopia8091
    @ddystopia8091 3 หลายเดือนก่อน

    Just use language that supports immutability natively, like Rust

  • @user-tk2jy8xr8b
    @user-tk2jy8xr8b 4 หลายเดือนก่อน +1

    Always hated the IsReadOnly concept

  • @constexprDuck
    @constexprDuck 4 หลายเดือนก่อน +3

    Cat 🐈

  • @aphex0008
    @aphex0008 4 หลายเดือนก่อน

  • @thewelder3538
    @thewelder3538 3 หลายเดือนก่อน

    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  3 หลายเดือนก่อน

      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 3 หลายเดือนก่อน

      @@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__ 3 หลายเดือนก่อน

      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.

  • @MaVats
    @MaVats 4 หลายเดือนก่อน +2

    This is very similar to how Java UnmodifiableList works.

    • @yonishachar1887
      @yonishachar1887 4 หลายเดือนก่อน

      You are both right and wrong:
      Java's unmodifiable list are based on the Decorator pattern(wrapping the Collection), at least they built the Collection heirarchy in a way that makes sense.

    • @Scorbutics
      @Scorbutics 4 หลายเดือนก่อน

      @@yonishachar1887 You're right, but they "decorate" by subtracting the initial contact, which violates LSP

    • @FlaviusAspra
      @FlaviusAspra 4 หลายเดือนก่อน

      ​@Scorbutics it doesn't violate LSP in this case because it's covariant.

  • @semod8614
    @semod8614 25 วันที่ผ่านมา

    More dunking on Microsoft please. Their nonsensical approach to software design is a menace. They've somehow managed to monetize the confusion that they sow by selling you more products to "solve" issues created by their other products.

  • @codeSurvivor
    @codeSurvivor 4 หลายเดือนก่อน

    we need more cat time

    • @ChristopherOkhravi
      @ChristopherOkhravi  4 หลายเดือนก่อน +1

      But cats always need more nap time 😊

  • @svorskemattias
    @svorskemattias 4 หลายเดือนก่อน

    Even NULL violates LSP

  • @bithon5242
    @bithon5242 3 หลายเดือนก่อน +1

    I wish my girlfriend explained things these clearly

  • @7th_CAV_Trooper
    @7th_CAV_Trooper 4 หลายเดือนก่อน

    As soon as you start adding enums to your classes you need to think about adding new classes instead.

    • @ChristopherOkhravi
      @ChristopherOkhravi  4 หลายเดือนก่อน +1

      I suspect you are referring to Enumeration types and not Enumerables (which is discussed in this video) 😊😊

    • @7th_CAV_Trooper
      @7th_CAV_Trooper 4 หลายเดือนก่อน +1

      @@ChristopherOkhravi correct. Like the IsReadOnly bool on ICollection. Not an enum, but a clear indicator that they needed a new type rather than a flag.

  • @uuuuuu352
    @uuuuuu352 4 หลายเดือนก่อน

    11:27

  • @perfectketchup
    @perfectketchup 4 หลายเดือนก่อน +1

    Why do you elongate 3 min video to 18. Time is a valuable resource

  • @carlseghers7822
    @carlseghers7822 3 หลายเดือนก่อน

    Technically, if iEnumerable represents the idea of infinite number of elements, and iCollection the idea of a finite number of elements, then inheriting iCollection from iEnumerable is a violation of LSP, because code that deal with iEnumerable cannot make the infinite assumption if you pass in an iCollectible.. It's like why a iSquare cannot inherit from a iRectangle, because code dealing with rectangles would assume that height and width are independent, which is not the case with a square.. I think the inheritance of iCollectable from iEnumerator is ok because in reality nothing is infinite, but you cannot describe as property that iEnumerator assumes infinity and iCollection not..

    • @ChristopherOkhravi
      @ChristopherOkhravi  3 หลายเดือนก่อน +1

      Good and interesting point. Thanks for sharing 😊🙏. IEnumerables are *possibly* infinite. So in my interpretation we should read this as that finality (and size) is undefined. So imho this doesn’t lead to a violation when we say that a type where finality IS defined implements the one where it isn’t. Thanks again for your detailed comment 😊