Open bar4488 opened 4 weeks ago
Summary: The issue arises when two mixins declare the same member with different bounds. The type of the latter mixin member must conform to the type of the first mixin member, even if the class using the mixin can satisfy both types. This leads to an invalid override error, even when the class provides a valid implementation.
The problem being reported is that the class Object with Shooter, Bomber
(the superclass of Combatant
) has an invalid override.
The class Object with Shooter
has a member LongRangeWeapon get weapon;
.
The class Object with Shooter, Bomber
has that class as superclass, and then declares a member with signature ExplosionWeapon get weapon;
Since ExplosionWeapon get weapon;
is not a valid override of LongRangeWeapon get weapon;
, that class is invalid.
That class exists! It might be abstract, anonymous and generally inaccessible (other than through super
calls inside Combatant
), but the language doesn't care. The class exists and has to be valid. Also because the interface of that class is the interface that Combatant
inherits.
If you need to inherit multiple independent abstract declaration, it's better to use interfaces. Those are all added to the same class, and can be overridden by that classs. Mixins are applied sequentially, and all the intermediate classes must be valid.
I see, it would be really great if we could support such use-cases. This patten seems quite common in order to describe complicated traits tree.
It seems that a support for extended types would solve this problem, and also allow much more flexibility to the type system:
class A{}
mixin B on A{}
mixin C on A{}
typedef D = A with B,C
This would also allow for a class to declare members with type D, thus solving the problem stated in the issue.
Is there any issue open to support such a feature?
Not sure what such extended types world be. You can write
class D = A with B, C;
today, but it has the same issue because it does introduce the intermediate mixin application classes too.
I am not aware of any proposal that would remember this issue.
Such a feature would change how mixin application works, either by removing some normal class constraints from the anonymous mixin application classes, or by collapsing mixin applications into a single class (like being augmentations instead of separate classes, but then not having the same constraints as augmentations).
Maybe the solution is to use interfaces to drive the combined types, and only use mixins for the final implantation, with no two mixins containing the same member, not even as abstract. Or using generics for anything that differs between subclasses.
mixin LongRangeWeapon {}
mixin ExplosionWeapon {}
class Shotgun with LongRangeWeapon, ExplosionWeapon {}
mixin Shooter<W extend LongRangeWeapon> {
W get weapon;
}
mixin Bomber<W extends ExplosionWeapon> {
W get weapon;
}
abstract class Combatant<W extends Shotgun> with Shooter<W>, Bomber<W> {
@override
W get weapon;
}
// Or, of Combatant will not be extended
abstract class Combatant with Shooter<Shotgun>, Bomber<Shotgun> {
@override
Shotgun get weapon;
}
It seems that if 2 mixins declare the same member with different bounds, the type of the latter mixin member must conform to the type first mixin member, which can throw an error even in cases where the class using the mixin is able to satisfy both types.
expected behavior: There should not be any error as long as the class itself validly satisfies both mixin.