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

Respect IReadOnlyList<T> in the BCL #24793

Closed
weitzhandler opened this issue Jan 25, 2018 · 10 comments
Closed

Respect IReadOnlyList<T> in the BCL #24793

weitzhandler opened this issue Jan 25, 2018 · 10 comments
Labels
area-System.Collections question Answer questions and provide assistance, not an issue with source code or documentation.
Milestone

Comments

@weitzhandler
Copy link
Contributor

The following condition appears in many variations plenty of times throughout the BCL, especially in LINQ, (From ElementAt):

if (source is IList<TSource> list)
{
    return list[index];
}

But there is also IReadOnlyList<T> which provides the same thing and is not considered because it doesn't overlap with IList<T>, and the fact that random access is provided by it is neglected in the BCL.
Why is that?

Similar to ICollection<T> and IReadOnlyCollection<T>, see #23337.

@ikopylov
Copy link
Contributor

The main reason for that is the performance overhead: every additional type cast adds its own cost and the cost of cast to variant generic interface is much higher.

Corresponding issue https://github.com/dotnet/coreclr/issues/603

@weitzhandler
Copy link
Contributor Author

But going O(n) on a random access collection?

@ikopylov
Copy link
Contributor

Due to historical reasons all collections from BCL that implement IReadOnlyList<T> also implement IList<T> (even immutable ones). For the third-party libraries this is also true in most cases. As a result, in majority number of sitations it is enough to check only for IList<T> implementation.

LINQ is often used on a hot path, so an additional type check may result in regression for most use-cases. ElementAt is somewhat special and perhaps can also check for IReadOnlyList<T>. But that change should be tested by benchmarks and in the real-world scenarious.

@weitzhandler
Copy link
Contributor Author

So what's the point I implementing IReadOnlyList<T> as a gateway to random access if not always respected by the BCL?

@rvhuang
Copy link

rvhuang commented Feb 4, 2018

For the third-party libraries this is also true in most cases.

@ikopylov That always sounds a bit weird to me because it suggests that IList<T> and IReadOnlyList<T> have underlying connection and have been implicitly coupled but they actually shouldn't (same situation for ICollection<T> and IReadOnlyCollection<T>).

If we can't add read-only interface check to existing Enumerable extensions, the only solution that I can come up with so far is to provide a new set of extension methods that are specially optimized for index-supported series. Just like we have AsParallel() which enables PLINQ and AsQueryable() which enables expressions, we can also have something like AsIndexable() to enable the wrapper.

I know my suggestion sounds stupid. Feel free to laugh at me. 😞

@svick
Copy link
Contributor

svick commented Feb 4, 2018

@rvhuang I don't think your suggestion is stupid. But I do think it has roughly zero chance of being included in corefx. That's because it might offer some performance improvements in theory, but it won't do that in practice. And it doesn't make sense to add an API whose only purpose is to improve performance, if it won't actually improve performance.

And if you have a library of collections where AsIndexable() would help, you could include it in that library.

@rvhuang
Copy link

rvhuang commented Feb 5, 2018

That's because it might offer some performance improvements in theory, but it won't do that in practice.

@svick In fact performance is not the thing I wanted to point out. The actual one is here as I mentioned.

it suggests that IList<T> and IReadOnlyList<T> have underlying connection and have been implicitly coupled but they actually shouldn't.

This is one thing that I would consider API design flaw as you can't implement IReadOnlyList<T> only or you will get random access.

@weitzhandler
Copy link
Contributor Author

weitzhandler commented Feb 5, 2018

@rvhuang
This is one thing that I would consider API design flaw as you can't implement IReadOnlyList only or you will get random access.

Exactly! Same thing bother me with ICollection. There supposed to be a common Count property.

But performance also counts. Accessing a list in linear fashion when an index/count is available is waste of resources, especially with bigger lists (See ICountable #23337).

@msftgits msftgits transferred this issue from dotnet/corefx Jan 31, 2020
@msftgits msftgits added this to the Future milestone Jan 31, 2020
@Soon5
Copy link

Soon5 commented Jul 4, 2020

This is one thing that I would consider API design flaw as you can't implement IReadOnlyList<T> only or you will get random access.

I second that. I was just implementing a new class with only Implementing IReadOnlyList. If I also have to implement IList so I can use it with LINQ properly, the whole Idea of having a ReadOnly Interface is gone.

@eiriktsarpalis
Copy link
Member

This is related to #42254, I'm going to close this so that we can consolidate the conversation in one issue.

@ghost ghost locked as resolved and limited conversation to collaborators Dec 18, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-System.Collections question Answer questions and provide assistance, not an issue with source code or documentation.
Projects
None yet
Development

No branches or pull requests

7 participants