meetings/2021/LDM-2021-11-10.md
https://github.com/dotnet/csharplang/issues/5413
Today, we took a first look at adding a self type constraint to C#, as part of the work on generic math in C#. We see 3 main problems that the self type constraint could address:
interface INumber<T> where T : INumber<T>.
This is quite verbose, requiring stating the name of the interface twice, and even a small reduction to interface INumber<T> where T : this helps both
with the number of characters typed and the clarity of the intent of the code.T implemented must be the current type. For example, someone could do struct MyStruct : IAdditiveIdentity<int>,
because int implements IAdditiveIdentity<int>. CRTP involving operators will naturally enforce that T is actually the current type, because of the rules
around operator implementation, but this is complex from both a spec perspective and an implementation perspective.Of these concerns, we think the best motivation for self types is actually the first one. For concern 2, we're unsure what the real harm is. Yes, users can
provide an odd implementation of one of these interfaces, but that's going to be true forever in C# regardless of our decision here, unless we take a breaking
change to IEquatable<T> and similar interfaces that shipped with C# 2. It does simplify some rules for the compiler, but ultimately we're not sure that
addressing concern 2 is a motivating factor.
Concern 3 is valid, but we're not sure the self type is the appropriate way to fix it. We've had base calls for DIMs on the backlog for a few years now, and
we see the possibility for a more generalized way to call a specific implementation of a method on a type. The current design for the self type happens to
address this concern, but not in a generalized fashion. In addition, several members of the LDM are not convinced by the prevalence of the need to call these
implementations once .NET 7 is out: they do exist, but how common will needing those implementations be?
We also talked about the possibility of using associated types to represent the self type, rather than a public type parameter. While this is somewhat attractive,
we're in general agreement that unless we have real runtime support for an associated self type, we don't want to take this direction. In C#, we generally avoid
having metadata significantly differ from the source; if the metadata needs to have a generic type parameter, then we would like the source to indicate such.
At some point, associated types need to be translated into the universal type space, which will spread virally throughout the program: that either needs to be
done at compile time by Roslyn (the representation change we want to avoid), or it needs to be done by the runtime. The runtime has concerns about avoiding an
MxN problem (where M methods will need to be specialized N times) without whole-program analysis, which is not always available. There's also some argument that,
of all the things associated types can do, the self type is one of the least interesting ones. Consumers of the generic math feature will almost certainly still
need to use a generic type parameter, because unless they're creating a method with one input and no outputs, they will need to constrain each input and output to
be the same associated type, not just some associated self type. IE, using a hypothetical INumber.this syntax:
// How is the compiler to know that the `INumber.self` of the `left` parameter is the same as the `INumber.self` of the `right` parameter, and how does it make
// any assumptions about the return type?
public INumber.self Add(INumber.self left, INumber.self right) => left + right;
// Users would actually need to resort to generics to relate these parameters:
public T Add<T>(T left, T right) where T : INumber.self => left + right;
Given that we see the vast majority of the usages of the self type being consumption, not definition, we're unsure the potentially significant cost of the associated->universal type translation actually buys the user anything.
We're going to have a small group explore this space more and make revisions to the proposal before coming back to LDM.