From de225ff217b8aabd6b45a9882327b8772d10136e Mon Sep 17 00:00:00 2001 From: Mads Torgersen Date: Thu, 1 Jun 2017 16:50:17 -0700 Subject: [PATCH] Add design notes --- meetings/2017/LDM-2017-04-11.md | 53 +++++++++++++++------------------ meetings/2017/README.md | 4 +++ 2 files changed, 28 insertions(+), 29 deletions(-) diff --git a/meetings/2017/LDM-2017-04-11.md b/meetings/2017/LDM-2017-04-11.md index a6f8315..0eb495b 100644 --- a/meetings/2017/LDM-2017-04-11.md +++ b/meetings/2017/LDM-2017-04-11.md @@ -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`, `IReadOnlyList` and `IList` 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! \ No newline at end of file +We should look more deeply into what Java does here. There must be accumulated insight already on this topic. \ No newline at end of file diff --git a/meetings/2017/README.md b/meetings/2017/README.md index 33bb2b0..bdb0b64 100644 --- a/meetings/2017/README.md +++ b/meetings/2017/README.md @@ -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