csharplang/meetings/2017/LDM-2017-04-19.md
2017-04-19 17:14:50 -07:00

2.5 KiB

C# Language Design Notes for Apr 19, 2017

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

"I'm not thrilled with the decision, but it was a constrained call"

Improved common type

b ? null : 7 // should be int?

This is a small, isolated change that leads to a nice improvement. Let's do it!

Diamonds with classes

The class should always win. It's implementation in a class is more specific. "Does the class implement this member? No, then look for a default implementation".

structs and default implementations

Very hard to use default implementations from structs.

Referring to the IB example in the issue.

Only way:

public static void Increment<T>(ref T t) where T : IB => t.Increment();

Even that won't necessarily avoid boxing! What is the type of this in the implementation of IB.Increment? If it's IB, then this is a boxed form of the struct! We can avoid that by having an implicit type parameter, a "this type", which is constrained by IB. But then, if that doesn't have a name, you can't use it in the body. If it does have a name, do we need a syntax for that?

For inherited members on structs today, they do in fact get boxed, but it is never observable - because of the behavior of those three methods (ToString, etc.).

We can't do 1. - it would undermine the value of the feature. (Because adding a new interface member with a default implementation would break implementing structs).

Number 2. pushes the problem elsewhere, at a high cost and with a high risk that you box later anyway.

Number 3. looks like a cop out but there really doesn't seem like a good alternative. C# already has places where structs and interfaces behave weirdly together.

Can we make it so that structs inherit default interface members? That would almost certainly make it breaking.

Conclusion

Let's stick with 3. It would be a breaking change to do 2 later, so we can never change it.

Base invocation

Like classes it should generate a non-virtual call.

I.base.M()
base(I).M()
base<I>.M()

base(I) is the winner. It works like default(T).

Should these be permitted in classes too, to get base interface implementations? Yes.

We could actually expand it to classes too, to allow a more distant base implementation to be called. Let's decide that later.

Question: In an interface, can I say base(IA) that isn't a direct base interface? Yes. Question: In a class, can I say base(IA) that isn't a direct base interface? Yes.