dotnet / runtime

.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.
https://docs.microsoft.com/dotnet/core/
MIT License
15.05k stars 4.69k forks source link

[API Proposal]: Implement IEnumerator<T> on ref struct enumerators #105276

Open stephentoub opened 2 months ago

stephentoub commented 2 months ago

Background and motivation

We've shipped multiple ref struct enumerators. Previously they couldn't implement IEnumerator<T>, but now they can. We should have them do so.

API Proposal

namespace System
{
    public static class MemoryExtensions
    {
        public ref struct SpanSplitEnumerator<T>
+           : IEnumerator<Range>
    }
    public readonly ref struct ReadOnlySpan<T>
    {
        public ref struct Enumerator
+           : IEnumerator<T>
    }
    public readonly ref struct Span<T>
    {
        public ref struct Enumerator
+           : IEnumerator<T>
    }
}
namespace System.Text
{
    public ref partial struct SpanLineEnumerator
+       : IEnumerator<ReadOnlySpan<char>>

    public ref partial struct SpanRuneEnumerator
+       : IEnumerator<Rune>
}
namespace System.Numerics.Tensors
{
    public readonly ref struct ReadOnlyTensorSpan<T>
    {
        public ref struct Enumerator : 
+           : IEnumerator<T>
    }
    public readonly ref struct TensorSpan<T>
    {
        public ref struct Enumerator : 
+           : IEnumerator<T>
    }
}
namespace System.Text.RegularExpressions
{
    public ref struct ValueMatchEnumerator
+       : IEnumerator<ValueMatch>

    public ref struct ValueSplitEnumerator
+       : IEnumerator<Range>
}

Notes:

API Usage

static int Sum<TEnumerator>(TEnumerator enumerator) where TEnumerator : IEnumerator<int>
{
    int sum = 0;
    while (enumerator.MoveNext()) sum += enumerator.Current;
    return sum;
}

Alternative Designs

No response

Risks

No response

dotnet-policy-service[bot] commented 2 months ago

Tagging subscribers to this area: @dotnet/area-system-runtime See info in area-owners.md if you want to be subscribed.

KennethHoff commented 2 months ago

I thought "ref structs implementing interfaces" were being postponed/preview for .Net 9(?)

stephentoub commented 2 months ago

I thought "ref structs implementing interfaces" were being postponed/preview for .Net 9(?)

No, it's planned for C# 13.

And this proposal is for .NET 10.

KennethHoff commented 2 months ago

I thought "ref structs implementing interfaces" were being postponed/preview for .Net 9(?)

No, it's planned for C# 13.

It sounds to me like it's (at least being set up to be) in preview for C# 13 https://github.com/dotnet/roslyn/issues/73923

And this proposal is for .NET 10.

That's true 😅

stephentoub commented 2 months ago

I thought "ref structs implementing interfaces" were being postponed/preview for .Net 9(?)

No, it's planned for C# 13.

It sounds to me like it's (at least being set up to be) in preview for C# 13 dotnet/roslyn#73923

That is out of date.

KennethHoff commented 2 months ago

I thought "ref structs implementing interfaces" were being postponed/preview for .Net 9(?)

No, it's planned for C# 13.

It sounds to me like it's (at least being set up to be) in preview for C# 13 dotnet/roslyn#73923

That is out of date.

Welp 😅

stephentoub commented 2 months ago

https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-07-22.md#ref-structs-implementing-interfaces

KennethHoff commented 2 months ago

https://github.com/dotnet/csharplang/blob/main/meetings/2024/LDM-2024-07-22.md#ref-structs-implementing-interfaces

If only that had been released just a few hours prior 🫠😂

huoyaoyuan commented 2 months ago

Even with interfaces on ref structs, we still can't make ref struct implementing IEnumerable<T>, because the enumerator can't be boxed as IEnumerator<T>, right?

There was long-standing discussion to make an abstraction of non-boxing enumerator. Now ref structs forces everything to be non-boxing. Is there any interest to revisit this area?

timcassell commented 2 months ago

@huoyaoyuan You mean like IEnumerable<T, TEnumerator> where TEnumerator : IEnumerator<T>?

I think that hasn't happened so far because C#'s generic inference doesn't work on it, forcing the full generics to be typed out, which is less than ideal.

huoyaoyuan commented 2 months ago

@huoyaoyuan You mean like IEnumerable<T, TEnumerator> where TEnumerator : IEnumerator<T>?

I think that hasn't happened so far because C#'s generic inference doesn't work on it, forcing the full generics to be typed out, which is less than ideal.

Yes. But of course if we start to do so, we need also to define an approach to seamless adapt IEnumerable<T> to it, to not create yet another discrepancy.

alrz commented 2 months ago

static int Sum<TEnumerator>(TEnumerator enumerator)

Is there a proposal to implement linq operators with TEnumerator? (I think that would be related to https://github.com/dotnet/runtime/issues/64031 somehow)

stephentoub commented 2 months ago

static int Sum<TEnumerator>(TEnumerator enumerator)

Is there a proposal to implement linq operators with TEnumerator? (I think that would be related to #64031 somehow)

No, we don't plan to do that.

terrajobst commented 1 month ago

Video

namespace System
{
    public partial static class MemoryExtensions
    {
        public partial ref struct SpanSplitEnumerator<T> : IEnumerator<Range>
        {
        }
    }
    public readonly ref struct ReadOnlySpan<T>
    {
        public partial ref struct Enumerator : IEnumerator<T>
        {
        }
    }
    public readonly ref struct Span<T>
    {
        public partial ref struct Enumerator : IEnumerator<T>
        {
        }
    }
}
namespace System.Text
{
    public partial ref struct SpanLineEnumerator : IEnumerator<ReadOnlySpan<char>>
    {
    }
    public partial ref struct SpanRuneEnumerator : IEnumerator<Rune>
    {
    }
}
namespace System.Numerics.Tensors
{
    public readonly ref struct ReadOnlyTensorSpan<T>
    {
        public partial ref struct Enumerator : IEnumerator<T>
        {
        }
    }
    public readonly ref struct TensorSpan<T>
    {
        public partial ref struct Enumerator : IEnumerator<T>
        {
        }
    }
}
namespace System.Text.RegularExpressions
{
    public partial ref struct ValueMatchEnumerator : IEnumerator<ValueMatch>
    {
    }
    public partial ref struct ValueSplitEnumerator : IEnumerator<Range>
    {
    }
}