Add design notes
This commit is contained in:
parent
efe200cf04
commit
de225ff217
2 changed files with 28 additions and 29 deletions
|
@ -1,47 +1,42 @@
|
||||||
# C# Language Design Notes for Apr 11, 2017
|
# C# Language Design Notes for Apr 11, 2017
|
||||||
|
|
||||||
|
## Agenda
|
||||||
|
|
||||||
***Raw notes, yet to be cleaned up - read at your own peril***
|
1. Runtime behavior of ambiguous default implementation
|
||||||
|
|
||||||
|
|
||||||
|
# Runtime behavior of ambiguous default implementation
|
||||||
|
|
||||||
#406 issues
|
The feature is intended to work when a new default-implemented member is added to an interface `I`, even when an implementing class `C` is not recompiled. So the runtime needs to know about default implementations and be able to find them.
|
||||||
|
|
||||||
## Binary compat 1
|
In the case of overrides, there may be diamond-hierarchy cases where the compiler knows of only one override, but one is added later to another interface. The implementations are now ambiguous, and a recompilation would cause an ambiguity, but it would seem desirable that the runtime should choose "the one the compiler new about"; that, somehow, that knowledge would be baked in to the compiled class `C`.
|
||||||
|
|
||||||
The essence is: Does the compiler encode where it gets its implementation from? The answer is no: the runtime gets to look it up. This is similar to classes.
|
Starting out with these type declarations in separate assemblies:
|
||||||
|
|
||||||
## Binary compat 2
|
``` c#
|
||||||
|
interface I1 { void M() { Impl1 } }
|
||||||
|
interface I2 : I1 { override void M() { Impl2 } }
|
||||||
|
interface I3 : I1 { }
|
||||||
|
class C : I2, I3 { }
|
||||||
|
```
|
||||||
|
|
||||||
This is in some way a counterexample, because it *would* be resolved if the compilation of C had encoded its choice.
|
Everyone's happy, and `C`'s implementation of `M` would unambiguously come from `I2`.
|
||||||
|
|
||||||
Stake in the ground: fine to fail at compile time, but not at runtime!
|
Now `I3` is modified and recompiled:
|
||||||
|
|
||||||
You can't always bake in, because the class may be compiled before the default-implemented member was even added to the interface.
|
``` c#
|
||||||
|
interface I3 : I1 { override void M() { Impl3 } }
|
||||||
|
```
|
||||||
|
|
||||||
|
What should happen at runtime? When `C` was compiled, it "thought" everything was alright. At runtime it isn't. Can the compilation of `C` bake in a preference based on its understanding of the world at the time of compilation? Should it?
|
||||||
|
|
||||||
Choices:
|
It is not obvious how this would work. What if the default implementation `C` depends on is moved, deleted or overridden? Should it just be a "vague" preference in case of ambiguity, to get the runtime on the right track?
|
||||||
|
|
||||||
1. Error
|
This seems complicated, fragile and fraught with peril, but ending up with an ambiguity at runtime is also bad.
|
||||||
2. Deterministically pick one of the most specific ones
|
|
||||||
3. Choice baked into class (can't always work)
|
|
||||||
1. and if fails, then 1
|
|
||||||
2. and if fails, then 2
|
|
||||||
|
|
||||||
This example is represented by `IEnumerable<T>`, `IReadOnlyList<T>` and `IList<T>` in the BCL today.
|
Regardless, there will always be runtime ambiguities; "baking in" preferences would only address a subset. Two open questions:
|
||||||
|
|
||||||
Either way, there remains a choice between 1 and 2. Is it better to fail fast, or have arbitrary behavior?
|
1. Should we try to help resolve ambiguities by baking in compile time preferences? Unresolved.
|
||||||
|
2. Should we fail or pick an "arbitrary" implementation in case of inevitable ambiguities at runtime? Unresolved. Bad to error. Bad to run "arbitrary" code.
|
||||||
|
|
||||||
We can imagine situations where it's quite unfortunate that other code than "expected" gets run.
|
We should look more deeply into what Java does here. There must be accumulated insight already on this topic.
|
||||||
|
|
||||||
Further work:
|
|
||||||
- Understand what Java *actually* does, versus specs, and what fallout there has been
|
|
||||||
- Understand where these examples apply to our BCL, for example
|
|
||||||
|
|
||||||
Poll:
|
|
||||||
Runtime pick: 11
|
|
||||||
Error: 11
|
|
||||||
Burn in then pick: 111
|
|
||||||
Bake in and fail: 11
|
|
||||||
|
|
||||||
Not very decisive!
|
|
|
@ -145,3 +145,7 @@ Design some remaining 7.1 features
|
||||||
2. Inferred tuple element names
|
2. Inferred tuple element names
|
||||||
3. Tuple element names in generic constraints
|
3. Tuple element names in generic constraints
|
||||||
|
|
||||||
|
## Apr 11, 2017
|
||||||
|
[C# Language Design Notes for Apr 11, 2017](LDM-2017-04-11.md)
|
||||||
|
|
||||||
|
1. Runtime behavior of ambiguous default implementation
|
||||||
|
|
Loading…
Reference in a new issue