-
Notifications
You must be signed in to change notification settings - Fork 4.9k
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
[API Proposal]: List<T>.Slice #66773
Comments
Tagging subscribers to this area: @dotnet/area-system-collections Issue DetailsBackground and motivation
In addition, we should at some point go through all of API Proposalnamespace System.Collections.Generic
{
public class List<T>
{
+ public List<T> Slice(int start, int length);
}
} API Usage// Fancy the value
var c = new List<int>() { 1, 2, 3, 4 };
var cSlice = c[1..3];
// Getting the values out
foreach (var v in cSlice)
Console.WriteLine(v); Alternative DesignsThere are two options:
RisksWill users be confused that slicing allocates a new list, and doesn't refer to locations in the original list? Arrays slicing has the same behavior, and it is the standard behavior in the BCL (Slice always returns the containing type, not a different type), but it's something to consider.
|
... personally, I would prefer slices refer back to sections in the original collection. This is how |
I might agree, but unfortunately the ship on this has sailed, so I think it's better to be consistent with existing behavior. In arrays, for example, it's trivially easy to observe this behavior: int[] a = new() { 1, 2, 3 };
int[] b = a[..1];
a[0] = 2;
Console.WriteLine(b[0]); // Prints 1 If you changed those |
... for arrays, not for anything else, especially given the existing methods that do return subsections of existing data. |
For most sliceable types in the BCL. As I mentioned, the BCL has a rule that slice methods always return the containing type. The new ImmutableArray.Slice, for example, does this. The ship really has sailed here. |
Array is somehow different than List. There are many methods of list that modifies its size. If we add a check, it can also slow down normal lists. |
It'd be pretty easy to solve the overhead problem through an extension method and helper class (either in the BCL or in individual codebases). A simple API might be: public static IReadOnlyList<T> View<T>(this IReadOnlyList<T> list, Range range) => new ListViewHelper(list, range); There are a bunch of other and more flexible approaches (which I've wasted a bunch of time already pondering and refining before I realized the details don't actually matter here, just the general principle). I think it might actually be helpful for the BCL to include something to this effect, but it's simple enough to implement in individual projects or in a NuGet even if not. |
What would prevent us from having the slice method accept a |
Nothing. However, our existing pattern is to use an int parameter: see ImmutableArray.Slice. |
Sounds good. I guess we can debate during API review. @333fred would you like to champion the proposal? |
It seems public List<T> GetRange(int index, int count) Does that raise any concerns? |
|
Just gonna add, that ranges not working with anything but arrays really surprised me. I think the surprise of not being able to do var newDictionary = oldDictionary[..^4];
var newList = oldList[6..^3];
var newHashSet = oldHashSet[^19..]; and so on is more surprising than the surprise of allocating a new list. Working with lists in any capacity pretty much implies new alocations already. |
I wouldn't expect dictionaries or hashsets to be usable with slicing. They have no order, so what does "from the start until 4 from the end" even mean on a dictionary? |
You're right, yeah. |
After several years of having the slicing syntax in C# I have to say I find myself virtually never to use it. But maybe I'm in the minority here. I'm OK with the proposal here, but I have to say that I don't see a ton of value in it, especially because there is a |
GetRange does not work with slicing, including the new C# 11 feature. |
I don't think you're necessarily a minority, but you're missing out. It's great when you have a need for it, but I can't speak to how many people have a need. We've used it a fair bit though. I personally look forward to List support for slices. |
I'm excited to see the PR into HttpParser that uses an allocating |
Yea, I think @halter73 means the range syntax on spans, not on List. This feature I assume is the anti performance feature 😄 . |
I was not suggesting we would literally use List slices in the Kestrel's HttpParser. Only that in general, the new C# slicing syntax is nice to use if you need to do a lot of slicing. Not everything has the performance requirements Kestrel does. I use slices a lot in Python too. |
Understood; I was trying (and failing) to be funny. :) |
Understood. My point was that I don't use the syntax, so I don't see a huge difference in calling
I have tried to love it in parsing code, especially with strings and arrays/span but I find it way more difficult to read. My brain doesn't seem to warm up to the point where I can just look at range syntax and intuit what's going on. But as I said, I might be in the minority. If we believe there is customer demand for this, we can add it. |
namespace System.Collections.Generic
{
public class List<T>
{
+ public List<T> Slice(int start, int length);
}
} |
Allocations 📈📈📈 |
Closes dotnet#66773. I took the approach of just redirecting to GetRange, and using a Theory to make all direct GetRange tests run on both GetRange and Slice (and used list pattern syntax for the Slice version to make sure that's working end-to-end).
* Implement List<T>.Slice Closes #66773. I took the approach of just redirecting to GetRange, and using a Theory to make all direct GetRange tests run on both GetRange and Slice (and used list pattern syntax for the Slice version to make sure that's working end-to-end). * PR feedback. * Correct parameter names Co-authored-by: Eirik Tsarpalis <eirik.tsarpalis@gmail.com> Co-authored-by: Eirik Tsarpalis <eirik.tsarpalis@gmail.com>
Background and motivation
List<T>
is the most popular collection type in .NET, but it does not support slicing, which means that it doesn't work with the C# 7 or 11 language features that use slicing (listValue[1..]
andlistValue is [1, .. var rest]
).List<T>
is additionally based on arrays, which support slicing, but doesn't support slicing itself.In addition, we should at some point go through all of
System.Collections.Generic
, and figure out what types should have aSlice
method added to them, but I don't really have the time to take this inventory on.API Proposal
API Usage
Alternative Designs
There are two options:
System.Range
. We generally haven't been following this pattern in the BCL, but we could do so if we wanted.Risks
Will users be confused that slicing allocates a new list, and doesn't refer to locations in the original list? Arrays slicing has the same behavior, and it is the standard behavior in the BCL (Slice always returns the containing type, not a different type), but it's something to consider.
The text was updated successfully, but these errors were encountered: