Add design notes
This commit is contained in:
parent
efe200cf04
commit
de225ff217
|
@ -1,47 +1,42 @@
|
|||
# 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
|
||||
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 seems complicated, fragile and fraught with peril, but ending up with an ambiguity at runtime is also bad.
|
||||
|
||||
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.
|
||||
|
||||
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!
|
||||
We should look more deeply into what Java does here. There must be accumulated insight already on this topic.
|
|
@ -145,3 +145,7 @@ Design some remaining 7.1 features
|
|||
2. Inferred tuple element names
|
||||
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