Skip to content
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

Proposal: Add IsImmutable property to IReadOnlyCollection<T> and IReadOnlyDictionary<TKey,TValue> #20418

Closed
dmitriyse opened this issue Mar 3, 2017 · 8 comments
Labels
api-needs-work API needs work before it is approved, it is NOT ready for implementation area-System.Collections blocked Issue/PR is blocked on something - see comments
Milestone

Comments

@dmitriyse
Copy link

When dotnet/csharplang#52 feature will be added to C#/CLR (at least in restricted form), we will have ability to extend base BCL contracts.
This proposal rely on this suggestion and tries to solve ambiguous semantic of ICollection<T>.IsReadOnly property.

We needs a new property.

public interface IReadOnlyCollection<T>
{
     bool IsImmutable { get;}
}

public interface ICollection<T>
{
     bool IsImmutable { get;}
}

public interface IReadOnlyDictionary<T>
{
     bool IsImmutable { get;}
}

public interface IDictionary<T>
{
     bool IsImmutable { get;}
}

Let suppose we have two different collections both inherited from ICollection<T>

First example is when library allows to access some internal collection by the interface.

internal class PrivateCollection: ICollection<T>
{
     // Read methods allowed for library and for external usage.
     bool Contains(T item)
     {
           // Some valid implementation.
     }
     
     // This method is only allowed for some library internal classes.
     internal void Add(T item)
     {
           // Some valid imiplementation.
     }
     
     // Modification is closed for external users, but not for internal.
     void ICollection<T>.Add(T item)
     {
           throw new NotSupportedException();
     }
     
     public bool IsReadOnly
     {
           get
           {
                 // In this case true mean - this collection allowed to only read from ICollection<T>
                 // interface.
                 // But does not guaranties that collection will not be changed by some internal method.
                 return true;
           }
     }
}

this is ReadOnly meaning of IsReadOnly property.


Second collection can be well known ImmutableList

public class ImmutableList<T>: ICollection<T>
{
      bool ICollection<T>.IsReadOnly
      {
            get
            {
                  // Here it tells that collection is not only "ReadOnly" but also will never be changed by nobody.
                  return true;
            }
      }
}

Probably "it's too late" and we have tons of code one collections uses ReadOnly semantic
another Collections uses ReadOnly+Immutable semantic.

But now we can do the next improvement in the documentation:
IsReadOnly says that only:
all mutation method will return NotSupportedException or InvalidOperationException. And no any more guaranties.

@dmitriyse dmitriyse changed the title Proposal: Add IsReadOnly to IReadOnlyCollection<T> or IsImmutable extension method. Proposal: Add/Move IsReadOnly to IReadOnlyCollection<T> or IsImmutable extension method. Mar 3, 2017
@dmitriyse dmitriyse changed the title Proposal: Add/Move IsReadOnly to IReadOnlyCollection<T> or IsImmutable extension method. Proposal: Add/Move IsReadOnly to IReadOnlyCollection<T> or add IsImmutable extension method. Mar 3, 2017
@dmitriyse
Copy link
Author

Second approach I described in this issue https://github.com/dotnet/corefx/issues/16661

@svick
Copy link
Contributor

svick commented Mar 3, 2017

In many cases we needs to know if provided IReadOnlyCollection (actually "readable" semantic) is also "immutable".

Could you explain what those cases are? The one I can think of is when you're caching some collection and want to know if it's safe to cache it directly, or if you have to create a copy of it.

ICollection contains property IsReadOnly with exactly this logic.

That's not what ICollection<T>.IsReadOnly does. Consider this code:

var list = new List<int>();
ICollection<int> ro = new ReadOnlyCollection<int>(list);
Console.WriteLine(ro.IsReadOnly);
Console.WriteLine(ro.Count);
list.Add(1);
Console.WriteLine(ro.Count);

The output shows that even though ro.IsReadOnly returns true, ro is not immutable:

True
0
1

The documentation could be clearer about this.

@dmitriyse
Copy link
Author

This is very bad example because ReadOnlyCollection is a special case. Main purpose of this class is to save some collection from changes but allow to read collection content.
It's protects from guys who will do:

public void ReadMyCollection(IReadOnlyCollection<int> c)
{
    var mutableCollection = (ICollection<T>)c;
    // Make diversion
    c.Add(34);
}

IsReadOnly looks like have the problem with convention. IsReadOnly is ReadOnly or Immutable.
So we exactly trying to move from this dualism hell.

@dmitriyse
Copy link
Author

dmitriyse commented Mar 3, 2017

Probably the only solution would be adding new IsImmutable property.
We should analyze all BCL usages of IsReadOnly.

And finally write strict convention into all documentation.

@karelz
Copy link
Member

karelz commented Mar 3, 2017

@svick do you have documentation change proposal? We can ask docs folks to update it ...

@dmitriyse I still don't get your differentiation between IsReadOnly and IsImmutable, sorry. Do you have a small sample to demonstrate the difference? (something like @svick used above?)

@dmitriyse
Copy link
Author

dmitriyse commented Mar 3, 2017

I updated topic and there an answer.

@dmitriyse dmitriyse changed the title Proposal: Add/Move IsReadOnly to IReadOnlyCollection<T> or add IsImmutable extension method. Proposal: Add IsImmutable property to IReadOnlyCollection<T> and IReadOnlyDictionary<TKey,TValue> Mar 3, 2017
@karelz
Copy link
Member

karelz commented Mar 3, 2017

OK, so IsImmutable means that it is truly immutable and doesn't change any internal state (caching, etc.).
What are the scenarios when you need that information? As interface/collection class user isn't IsReadOnly sufficient for you?
Why do you need to know more about implementation details of the collection?

@karelz
Copy link
Member

karelz commented Mar 7, 2017

The motivation was discussed here: https://github.com/dotnet/corefx/issues/16661#issuecomment-284587410
It looks like this is a dupe (part of) the large issue.
We have to choose to either:

  • First clarify high-level motivation (as I mentioned maybe not on GitHub), then we can spin off smaller work items like this one, or
  • Spin off standalone API proposals (like this one) which can clearly express motivation and justification on their own.

Of course, let's open only API proposals which do NOT depend on not-yet-implemented C# features - in such case we should wait (see https://github.com/dotnet/corefx/issues/16818#issuecomment-284790069).

Closing as dupe for now, please let me know if you disagree.

@karelz karelz closed this as completed Mar 7, 2017
@msftgits msftgits transferred this issue from dotnet/corefx Jan 31, 2020
@msftgits msftgits added this to the 2.0.0 milestone Jan 31, 2020
@ghost ghost locked as resolved and limited conversation to collaborators Dec 25, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
api-needs-work API needs work before it is approved, it is NOT ready for implementation area-System.Collections blocked Issue/PR is blocked on something - see comments
Projects
None yet
Development

No branches or pull requests

4 participants