Shouldn't it go the other way?
All NonEmptyLists are Lists, but not all Lists are NonEmptyList.
So NonEmptyList inherits from List
Shouldn't it go the other way?
All NonEmptyLists are Lists, but not all Lists are NonEmptyList.
So NonEmptyList inherits from List
A NonEmptyList promises that its .Head method will always produce a value. An inherited List can not maintain that property, it must add either an error return or a possible exception (which is the same thing from this point of view), and so violates the LSP.
A List promises that if it has an element, you can remove it and have another List, whether by mutation or returning a new List. A NonEmptyList breaks that promise. If that sounds like a "so what", bear in mind that "removing an element" includes things like a "Filter" method, or a "split" method, or any of several other such methods beyond just iteration that a List is likely to have that a NonEmptyList is going to need a different type signature and/or exception profile to implement properly.
You could define a bare-bones superclass for both of them that allows indexing, iteration, appending, and a length method, without much else, and that does work. However, if you start trying to get very granular with that, across more data structures, you'll start to need multiple inheritance and that becomes a mess really quickly. There's a reason that, for instance, the C++ STL does not go the "inheritance hierarchy" route for this stuff.
Like I said, inheritance done properly is really restrictive. We often do a lot of sweeping under the rug without even realizing it, and that "works" but it still eats away at the architecture, all the more so if the people involved don't even realize what they are doing.
I don't follow. Remove the head from a NonEmptyList and the tail will be a List. It might not be a NonEmptyList, but that's not the contract of List.
List<'t> has a function TryUncons that gives Option<'t * List<'t>>
List<'t> does not have a method Uncons.
We can define TryUncons for NonEmptyList<'t> in terms of Uncons, specifically:
this.TryUncons() =
this.Uncons()
|> SomeIt would be an odd "object oriented language" list that lacked such things, e.g., https://docs.oracle.com/javase/8/docs/api/java/util/List.htm... . We're in OO land here, not FP land.
NonEmpty always has an element.
No. Removing an element from a NonEmptyList returns a List. LSP is respected when NonEmptyList is a List.