csharplang/meetings/2020/LDM-2020-06-29.md
2020-06-29 17:16:32 -07:00

5 KiB

C# Language Design Meeting for June 29th, 2020

Agenda

  1. Static interface members

Procedural Note

For the past few years, the LDM notes have been compiled by the wonderful Andy Gocke (@agocke). Andy is taking the next step in his career and moving to be the lead of the CLR App Model team as of today, and as such will be moving to LDT emeritus status, joining the ranks of our other former LDT members who form our advisory council. We thank him for all his hard work during his time as notetaker, collating the sometimes inane rambling of the LDM in a set of readable arguments and decisions.

At this point Fred Silberberg (@333fred) will be the new LDM notetaker. While I'll try to keep up much of the same spirit as Andy, I am not going to try to match his exact style or formatting, so there could be some changes in the exact formatting of the notes. I'll additionally apologize in advance as the notes inevitably end up delayed in the first few weeks as I settle in. And now, on to the meeting notes!

Quote of the Day

"So we spent these last 10 years making it so we can come back to this. We actually never forgot, [.NET Core] has all been a ploy to get statics into interfaces."

Discussion

Today @abock and @migueldeicaza presented their work on Partydonk over the past year, bringing abstract interface members to C# and the Mono runtime in a proof of concept. I did not take notes on the specific slides: all of that material is available publicly on the partydonk repo here.

Overall, the LDT members had a very positive reception to this work: in particular, they arrived at many of the same conclusions @CarolEidt had in her exploration of this space 10 years ago: much of the runtime work falls out from allowing abstract static in CIL and emitting constrained calls to such members during compilation. From a language perspective, there's still a bit of work to do. override on abstract static members defined in interfaces isn't particularly nice from a regularity with instance members perspective. We will also have to do design work around explicit implementations: it could all fall out from existing rules, but will need a critical eye to make sure that the consequences of explicitly implementing an abstract member, and what that really means.

The existing code uses a TSelf generic parameter in what could be considered kind of an unfortunate syntax:

interface INumeric<TSelf> where TSelf : INumeric<TSelf>
{
    abstract static TSelf Zero { get; }
    abstract static TSelf operator +(TSelf a, TSelf b);
}

The TSelf : where TSelf : INumeric<TSelf> was suggested in the past to help the prototype make progress without blocking on associated types, but it's ugly and proliferates through the entire type hierarchy if left unchecked. A much better solution would be to formally introduce associated types into the language, something that we've discussed in LDM before and has some support. We should take those into account here: if we introduce this entire type hierarchy, then in the next C# release introduce a TSelf associated type it would leave an annoying blemish on the language. In particular, we need to make sure we have a good roadmap for all components involved here: the compiler, the runtime, and the core libraries. Nonvirtual static members in interfaces have already shipped with C# 8, so we can't get that back and declared them virtual members of the interface.

We do still have a few language questions: today, you cannot create user-defined operators that involve interfaces, because doing so would subvert the type system. However, some numeric applications seem like they would want to be able to do this for constants (see IExpressibleByIntegerLiteral and IExpressibleByFloatLiteral in the presentation). If we allow this for the TSelf parameter, it seems like these concerns should be obviated: you're not converting to an interface type, you're converting to a concrete type and specifying that said conversion must be available for any implementations of the interface. Additionally there's an interesting correspondance issue: today, any members that are part of the interface contract are available on an instance of the interface. However, with static methods, the interface itself doesn't provide them: types that implement the interface provide them, but not the interface itself. We can certainly come up with new rules to cover this, but we will need to do so.

Some other miscellaneous topics that came up:

  • We could use this system to specify constructors with multiple parameters of a specific type. Static interface members could be implemented by a type calling new, which would allow us to improve on the simple new() that we have today.
  • Existing language built-in operators would need to be considered to satisfy the constraints of the numeric interfaces.