Skip to content

[Proposal]: Non-boxing default-interface methods #9969

@agocke

Description

@agocke

Non-boxing default-interface methods

Summary

When we added default interface methods we decided that the type of this is the interface method itself. For classes this is not a big deal. For structs, however, it implies boxing. This has implications not just for performance, but also semantics (side-effects). It would be great if we had a way to use the type of a generic parameter constrained to the interface rather than the interface itself.

There is already a potential encoding for this in the runtime type system:

public class C {
    public static void Main() {
        var s = new S(1);
        Console.WriteLine(s.M());
    }
}

interface IFace<TSelf> where TSelf : IFace<TSelf>
{
  static virtual int M(ref TSelf @this) => 0;
}

struct S(int x) : IFace<S>
{
    private readonly int _x = x;
    static int IFace<S>.M(ref S @this) => @this._x;
}

static class IFaceExt
{
    extension<T>(ref T @this) where T : struct, IFace<T>
    {
        public int M() => T.M(ref @this);
    }
}

Obviously this is a large amount of boilerplate. It would be nice for C# to help here. A simple proposal for syntax would be:

interface IFace<TSelf> where TSelf : IFace<TSelf>
{
   static this int M(ref TSelf @this) => 0;
}

Note the this in the modifier section. It would take the place of the virtual/abstract modifiers as those would no longer be necessary and could be inferred based on whether the member has a declared body.

Design meetings

Metadata

Metadata

Assignees

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions