csharplang/meetings/2017/LDM-2017-04-05.md
2017-04-05 16:03:55 -07:00

3.4 KiB

C# Language Design Notes for Apr 5, 2017

Raw notes, yet to be cleaned up - read at your own peril

interface I1
{
    void M1() { ... } // non-virtual
    virtual void M2() { ... }
}
interface I2
{
    void M1() { ... } 
    sealed void M2() { ... } // non-virtual
}
interface I3
{
    virtual void M1() { ... } 
    sealed void M2() { ... } // non-virtual
}

Do we want to allow non-virtual declarations in interfaces? In practice you probably at least want private methods. But it's likely you'll want internal, and maybe public.

For traits based programming, you'd want to have the same things available, when you "port things over" to a trait.

Intuitively it feels against the spirit of interfaces.

Should an interface be required to put abstract in order to allow derived interfaces to override them? No. So it probably also shouldn't require virtual.

So it's the "virtualness" that's implicit, not specifically the "abstractness".

The core motivator is the defaultness. So that is the thing we should design around.

Motivators:

  • Defaults are useful!
  • Java and Swift
  • Traits

Is the copy-paste sceario between interfaces and classes important? It already is very far from possible. property decl in interface today is auto-prop in class today!

itf I
{
    sealed void M() { ... }
    void N();
    void O() { ... }
}
cls C : I
{
    pub void M() => base(I).M();
}

Not requiring a modifier for non-virtual is dangerous: I go add a body, and nothing breaks. No implementors break either, as long as they are implementing implicitly. But then it means something different!

Decision 1: non-virtual should be explicitly expressed through sealed or private. Decision 2: sealed is the keyword to make interface instance members with bodies non-virtual Decision 3: We want to allow all modifiers in interfaces
Decision n: Default accessibility for interface members is public, including nested types Decision n+1: private function members in interfaces are implicitly sealed, and sealed is not permitted on them. Private classes can be sealed, and that means sealed in the class sense of sealed.

Absent a good proposal, partial is still not allowed on interfaces or their members.

tuple names

new { X = X, Y }; // {X,Y}

Projection initializer.

Action y = () => {}
var t = (x: x, y) // (int x, Action y) or (int x, Action)?
t.y(); // a call of the second component or of an extension method y?
(int, int) t = (x: x, y); // warning for x. No warning for y, because inferred

We dropped the feature because we didn't have partially named tuples, but now we do.

Options around breaking change:

  1. We don't want the feature
  2. We want it but it's too late
  3. We want it but it has to be now
  4. We want it and we don't care when - it's esoteric

We go for 2. Due to the forward breaking change it needs to be tied to a language version. Same rules as anonymous types: picked up from simple names, dotted names and ?.'ed names.

Let's aim for 7.1.

tuple names in constraints

We think you could never declare a class (in C#) that satisfies the constraints (in C#) in the examples. You could construct things in IL to circumvent, but it's ok for us not to deal with that. So it's maybe ok for C# not emit an error here.

We do try to emit an error when constraints conflict. But the value is low and it is hard and esoteric and makes the compiler slower.