Roslyn: ref structs should not implement interfaces

Created on 15 Jun 2017  路  8Comments  路  Source: dotnet/roslyn

Considering that ref structs cannot be boxed or passed as a generic type argument, implementing interfaces is pointless.

Area-Compilers Bug Language-C# New Language Feature - Readonly References

Most helpful comment

I guess it is because there is currently no way to constrain a generic type parameter to avoid possibly boxing it. Why not consider a constraint for this then? Not sure what would be good but:

internal interface ISwapper
{
    void Swap(int i, int j);
}
internal ref struct Swapper<T> : ISwapper // ref structs can't inherit interfaces :( Nor be generic type parameter
{
    Span<T> _items;

    public Swapper(Span<T> items)
    {
        _items = items;
    }

    public void Swap(int i, int j)
    {
        ref T start = ref _items.DangerousGetPinnableReference();
        SpanSortHelper.Swap(ref Unsafe.Add(ref start, i),
                            ref Unsafe.Add(ref start, j));
    }
}

public void SomeMethod<TSwapper>(TSwapper swapper)
    where TSwapper : ref struct 
    // Although it should still work for normal structs, just restrict the availability of boxing etc. 
    // "unboxable" :|
{
     // Swapper can then be used to inject zero, one or more extra items...
}

All 8 comments

What about IDisposable? A using statement requires the type to be IDisposable even if it dispatches the Dispose call to the method on a particular type.

Ref struct is not convertible to an interface, even if it claims to be implementing one. In particilar that would not satisfy the requirememts of using.

Well, we could change the requirements of using, as in #11420.

It is definitely not pointless, it can used with generics without boxing. Why can it not be used as a generic type argument?

I have a specific need that is blocked by this, namely for my work with Span.Sort?

I guess it is because there is currently no way to constrain a generic type parameter to avoid possibly boxing it. Why not consider a constraint for this then? Not sure what would be good but:

internal interface ISwapper
{
    void Swap(int i, int j);
}
internal ref struct Swapper<T> : ISwapper // ref structs can't inherit interfaces :( Nor be generic type parameter
{
    Span<T> _items;

    public Swapper(Span<T> items)
    {
        _items = items;
    }

    public void Swap(int i, int j)
    {
        ref T start = ref _items.DangerousGetPinnableReference();
        SpanSortHelper.Swap(ref Unsafe.Add(ref start, i),
                            ref Unsafe.Add(ref start, j));
    }
}

public void SomeMethod<TSwapper>(TSwapper swapper)
    where TSwapper : ref struct 
    // Although it should still work for normal structs, just restrict the availability of boxing etc. 
    // "unboxable" :|
{
     // Swapper can then be used to inject zero, one or more extra items...
}

I second @nietras. This limitation prevents the creation of a lot of very useful building blocks.

As a motivation consider this building block:

    public interface IAction<T>
    {
        void Do(ref T value);
    }

    public static unsafe void ForEach<A, T>(this Memory<T> memory, A action)
        where T : unmanaged
        where A : struct, IAction<T>
    {
        fixed (T *ptr = &memory.Span.GetPinnableReference())
        {
            var p = ptr;
            var e = ptr + memory.Span.Length;

            for (; p < e; ++p)
            {
                action.Do(ref *ptr);
            }
        }
    }

And then using this with some implementation:

    public struct PointlesSumAction : IAction<Char>
    {
        public Char sum;

        public void Do(ref Char value)
        {
            sum += value;
        }
    }

...

        {
            var a = new PointlesSumAction();
        myMemory.ForEach(ref a);
    }

With optimizations turned on, this compiles to a loop with Do inlined, and the range checks being done only once for the ForEach call.

This can be done with Memory now, but it really belongs to Span.

Was this page helpful?
0 / 5 - 0 ratings