dart-lang / dart-lang/language
Abstract members in mixin could be considered as originating in interface
- Dominant language
- TeX
- Stars
- 2.9k
- Forks
- 239
- Avg merge
- 2d 18h
- Merged PRs (30d)
- 14
Description
Thanks to @johnniwinther for pointing out an ambiguity in the spec in this area. Note that the test [issue41210a.dart](https://github.com/dart-lang/sdk/blob/master/pkg/front_end/testcases/general/issue41210a.dart) creates a situation which is somewhat similar to the one discussed here, and it serves as an example of a library that will behave differently if we adopt the proposal of this issue.
Consider the following program:
```dart
mixin M {
void m1(int i);
void m2() => m1(0);
}
class A {
void m1(int i, [int j = 0]) {}
}
class B extends A with M {}
void main() {}
```
The class `B` is an error because it has a superclass `A with M` which is an error because it is treated as a declaration of a subclass of `A` whose body contains the instance member declarations from `M` (and a set of implicitly induced constructors that aren't important in this context). The error arises because that superclass has a abstract instance member declaration `void m1(int i);` which is not a correct override of the declaration `void m1(int i, [int j = 0]) {}` in its superclass `A`.
However, it is not required for soundness that such an abstract declaration _D_ in a mixin must be a correct override of all declarations of `m1` in superinterfaces, it is sufficient that _D_ is compatible with those other declarations in the sense that it is possible to compute a combined member signature for `m1` when _D_ is included.
We can use a small rewrite to obtain a situation where this treatment is applied, and the resulting library has no errors with the current implementations of the analyzer as well as the common front end:
```dart
abstract class I {
void m1(int i);
}
mixin M implements I {
void m2() => m1(0);
}
class A {
void m1(int i, [int j = 0]) {}
}
class B extends A with M {}
void main() {}
```
We could treat abstract declarations _D1 .. Dk_ in a mixin _M_ as if they originated in an implicitly induced interface with a fresh name. That is, we could apply the above work-around implicitly to all mixins with abstract declarations.
This would improve the support for code reuse, because `M` could then specify minimal requirements on _D1 .. Dk_ (that is: on methods called on `this`, just enough to satisfy the actual calls), rather than being forced to specify a valid overriding declaration of each of _D1 .. Dk_ for each mixin application of `M`. This is (1) wasteful, because the minimal requirements allow for applying `M` to a larger set of superclasses, and (2) impossible because the set of actual superclasses to `M` cannot be predicted when `M` is declared. So we end up just having a somewhat arbitrary abstract declaration which is known to make the mixin applicable to a certain set of known superclasses, and then it may or may not have a spurious failure with superclasses that weren't predicted. (Or we apply the above work-around to eliminate those failures.)
We may wish to specify the rule slightly differently, though: We'd say that abstract declarations _D1 .. Dk_ in a mixin `M` must be correct overrides relative to declarations in all superinterfaces of `M` (that is, considering `on` and `implements`). This means that visible declarations in `M` must satisfy the constraints implied by `M`'s superinterfaces, not just something which is compatible with those constraints. At a mixin application of `M`, we'd still say that the abstract declarations from `M` are treated as members of an implicitly induced interface with a fresh name. This will give us the desired flexibility for mixin applications, and at the same time allow readers of a mixin declaration to trust each abstract declaration to satisfy all override requirements, just like every declaration (abstract or concrete) in a class must satisfy all override declarations.
The proposed change is non-breaking, it only changes some mixin applications from being an error to being accepted.
So, @jakemac53, @leafpetersen, @natebosch, @lrhn, @munificent, @stereotype441, WDYT?
Contributor guide
Research direction
Start by reading the issue41210a.dart testcase and the two Dart examples in this proposal. Compare how the analyzer and common front end currently handle abstract mixin members, then locate the relevant language specification rules. Done means the proposed mixin treatment is specified consistently and the affected behavior is covered by tests.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- dart
- Domain
- compilers
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100