-
Notifications
You must be signed in to change notification settings - Fork 4.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Covariant Immutable Collections #28911
Comments
@terrajobst and @AArnott The point that I am trying to make here is: Immutable collections should be covariant, even if the type system of .Net makes it hard to achieve it. At least it should be possible to unlock the feature as it is a property of immutable collections from a theoretical perspective. From a user perspective, I would like to see a unified and easy way to use this feature. Currently, an ImmutableArray allows to Castup, but for other immutable collections, I need to perform other tricks (like for a dictionary). In this proposal, I try to come up with a unified API design that makes it very easy to make use of the covariantly flavored collections. I am aware that expressions like |
I don't need this often, but I do like the idea. It was a while ago, but as I recall the reason we didn't do it this way is we were considering it being the only way. There was a very well written blog post by Eric Lippert describing how immutable collections could be created and rely on extension methods to achieve automatic covariance. That idea was dismissed pretty quickly because of its reliance on extension methods for the primary use cases. For instance, if I created a The hybrid approach you're proposing where you can opt into covariance but the basic functions don't require it isn't one I recall considering before. @terrajobst may remember more. |
Thanks @AArnott !
Again quite more expensive than the CastUp of
That way we wouldn't need to introduce a new interface, namespace and wouldn't need to add all the extension methods. |
I cannot find the same suggestion for task, e.g. |
I've my doubts about it being too much of a hurdle, considering the target audience is people who consciously choose to use immutable collections. I'd wager a large majority of .NET developers will rarely, if ever, come in contact with the concept of immutable collections. |
Due to lack of recent activity, this issue has been marked as a candidate for backlog cleanup. It will be closed if no further activity occurs within 14 more days. Any new comment (by anyone, not necessarily the author) will undo this process. This process is part of the experimental issue cleanup initiative we are currently trialing in a limited number of areas. Please share any feedback you might have in the linked issue. |
This issue will now be closed since it had been marked |
related: https://github.com/dotnet/corefx/issues/5164
having dedicated covariant interfaces for the different immutable collection types (and implementing them on the immutable collection classes) would allow to add extension methods that allow to add elements to an immutable covariant collection.
The extension methods could check if the incoming
IImmutableCovariantList<out T>
is already aImmutableList<T>
- which should be true most of the time - and in this case use all the specific methods, like insert, add, remove of that class. Otherwise, we'd need to create a newImmutableList<T>
and then operate on that new instance.Why all the trouble?
IReadonlyList<T>
. related: Make IImmutableList covariant like IReadOnlyList, IEnumerable etc. #16011. You'd have an immutable type, that when adding or removing an element would give you a new snapshot of exactly the same type, where this type is covariant.it looks like the idea works and doesn't seem to break anything
Basically it is just
IImmutableCovariantList<T>
implemented byImmutablelist<T>
System.Collections.Immutable.Covariance
)Down there in the tests you also can see that how c# treats an
ImmutableList<T>
as anIImmutableCovariantList<T>
to make adding an apple to a list of bananas work out. As a user you currently need to add the namespaceSystem.Collections.Immutable.Covariance
that I introduced to avoid blowing up the list of extension methods that you see in the intellisense list when working with a regularImmutableList<T>
.here is the issue about covariance for classes:
dotnet/roslyn#171
it will not happen.
even though immutable collections would highly benefit: Eric Lippert implementing a
class Stack<out T>
: https://stackoverflow.com/questions/2733346/why-isnt-there-generic-variance-for-classes-in-c-sharp-4-0/2734070#2734070 ...anyways, because of this unavailable CLR feature, the only way of introducing covariant types is via interfaces. so yes, the proposed solution is a hack. it hacks around the limitations of the underlying system by introducing an interface for each immutable collection class. An
ImmutableDictionary<TKey, TValue>
e.g. would implementIImmutableCovariantDictionary<TKey, out TValue>
. The interface is there to ship the covariance feature, which is not shippable without that "hack". So class and covariant interface would always come in pairs.A user just needs to include
System.Collections.Immutable.Covariance
in her/his using statements and she/he is now able to work withIImmutableCovariantDictionary<TKey, out TValue>
whenever the need arises. Therefore she/he can avoid more complicated code, which would do the same.In the implementation of the extension methods regarding
IImmutableCovariantArray<out T>
would internally use the CastUp idea. The API surface would not care about when optimizations like the CastUp idea are possible or not. It would work the same way for all the immutable collections, which would be beautiful.If in 10 years classes in .Net suddenly can have covariant type parameters, the interfaces would get obsolete and many extension methods would magically run faster as
list as ImmutableList<T>
would typically be true (even if the incoming list is actually of typeImmutableList<TDerived>
).if you look at the implementation it gets obvious that we could also return the classes on all extension methods.
e.g.
would act on
ImmutableList<Banana>
(seen asIImmutableCovariantList<IFruit>
) and returnImmutableList<IFruit>
. The user would not even need to deal with the interface.The text was updated successfully, but these errors were encountered: