csharplang/meetings/2017/LDM-2017-05-17.md

113 lines
3.8 KiB
Markdown
Raw Normal View History

2017-05-31 00:56:12 +02:00
# C# Language Design Notes for May 17, 2017
2017-06-20 02:05:12 +02:00
## Agenda
2017-05-31 00:56:12 +02:00
2017-06-20 02:05:12 +02:00
More questions about default interface member implementations
2017-05-31 00:56:12 +02:00
2017-06-20 02:05:12 +02:00
1. Conflicting override of default implementations
2. Can the Main entry point method be in an interface?
3. Static constructors in interfaces?
4. Virtual properties with private accessors
5. Does an override introduce a member?
6. Parameter names
# Conflicting override of default implementations
If at runtimes you have ambiguous overrides:
2017-05-31 00:56:12 +02:00
``` c#
interface I1 { void M1(); }
2017-06-20 02:05:12 +02:00
interface I2 : I1 { override void M1() { ... } }
2017-05-31 00:56:12 +02:00
interface I3 : I1 { override void M1() { ... } }
class C : I2, I3 {} // what happens when you load?
C x;
x.M1(); // what happens when you call?
```
2017-06-20 02:05:12 +02:00
This can happen without compiler complaint through certain orders of compilation.
2017-05-31 00:56:12 +02:00
Options:
1. throw on load
2. throw on call (like Java)
3. pick arbitrarily (but consistently)
4. bake in what you meant at compile time
2017-06-20 02:05:12 +02:00
1. always use the baked in one, error if it's gone
2. pick the unique one, fallback to baked-in if unsuccessful
2017-05-31 00:56:12 +02:00
Baking in causes a lot to hinge on recompilation. We should leave to the runtime to resolve the virtual call. So not 4. Also, 1 seems too harsh. If you don't call it, why complain? If you call an arbitrary method, that's a little dangerous: you can't reason about what the program does.
2017-06-20 02:05:12 +02:00
## Conclusion
2017-05-31 00:56:12 +02:00
Option 2 it is. We can throw. If we realize we were wrong about this later, we can move from there. No bake in.
2017-06-20 02:05:12 +02:00
# Can the Main entry point method be in an interface?
Yes. No good reason why not. Also, that's the least work.
2017-05-31 00:56:12 +02:00
2017-06-20 02:05:12 +02:00
# Static constructors in interfaces?
Probably, but let the runtime folks think about this. Reason is static fields. We could allow initializers for static fields, but not an explicit static constructor. Can think about adding later.
2017-05-31 00:56:12 +02:00
2017-06-20 02:05:12 +02:00
# Virtual properties with private accessors
In classes you can define a virtual property with private accessor. Allowed in interfaces? What does it mean? Probably disallow.
2017-05-31 00:56:12 +02:00
2017-06-20 02:05:12 +02:00
# Does an override introduce a member?
2017-05-31 00:56:12 +02:00
2017-06-20 02:05:12 +02:00
- Does it introduce parameter names?
2017-05-31 00:56:12 +02:00
- Does it introduce a new virtual method that could be implemented independently
If the call site sees two separately declared methods, that's already an ambiguity.
``` c#
interface I1 { void M1(); }
2017-06-20 02:05:12 +02:00
interface I2 { void M1() { ... } }
2017-05-31 00:56:12 +02:00
interface I3 : I1, I2 { override void M1() { ... } }
I3 x;
x.M1();
```
2017-06-20 02:05:12 +02:00
Should `I3` be allowed? Does it override both?
Should `x.M1()`;
2017-05-31 00:56:12 +02:00
2017-06-20 02:05:12 +02:00
Explicit override syntax removes the problem, but do we want to force people to always put the interface in front?
2017-05-31 00:56:12 +02:00
2017-06-20 02:05:12 +02:00
Java's solution does not help us, because independently declared interface members unify in Java.
2017-05-31 00:56:12 +02:00
Xamarin does not expect to need override. They'll just need to know whether there is a default implementation or not. They will need reflection support to query the default methods.
It's not an option to depend on order.
2017-06-20 02:05:12 +02:00
## Conclusion
`I3` is fine, but does not introduce a new member. So the call to `M1` is ambiguous. The work-around is to cast to one of the interfaces. However, oddly, you *can* call it through `base(I3)`.
2017-05-31 00:56:12 +02:00
# Parameter names
``` c#
interface I1 { void M1(int a); }
interface I2 : I1 { override void M1(int b); } // allowed to change parameter names?
I2 x;
x.M(a: 3); // allowed?
x.M(b: 4); // allowed?
```
The class behavior is to pick the most specific names, but that does mean that introducing an override (with different parameter names) can be a breaking change. But we could issue guidance to not change names in this situation.
From experience, people do intentionally change names on override, but others ask for features to prevent them from doing it!
2017-06-20 02:05:12 +02:00
Common scenario is implementing a generic instance. Going from `T` to `Dog`.
2017-05-31 00:56:12 +02:00
2017-06-20 02:05:12 +02:00
## Conclusion
2017-05-31 00:56:12 +02:00
Let's take the names from the original declaration, deliberately being inconsistent with the class rule for simplicity's sake.
2017-06-20 02:05:12 +02:00
New open question: what about `base(I2)` and parameter names?