I have reviewed the discussion in #4348 and pondered for a solution to the problem of the two interfaces that a class with own private members has:
- inside the containing library, the interface includes the private members
- outside, it does not.
This flaw is what makes possible that code from the same library, reachable from outside (through exports), taking as input an object of the said class, may discover that the private members are missing from the received object because its type is simply an implementation the public interface.
Illustration (common knowledge)
/* This is 'a.dart'. */
class I {
int get a => 10;
void _do() {
print("Doing stuff in I");
}
}
class II {
void _do() {
print("Doing stuff in II");
}
}
void doWith(I i) => i._do();
/* Run this file.*/
import "a.dart";
class AI /*extends II*/ implements I {
@override
int get a => 11;
void _do() {
print("Doing stuff in AI");
}
}
void main() {
doWith(AI());
}
The code above throws NoSuchMethodError.
Off topic, can anyone explain why the code works and prints Doing stuff in II if the comment delimiters around extends II are removed? 🤨 Is the compiler happy with any implementation of the private method _do(), as long as it originates from the same library, namey the totally unrelated class II ❓
Proposal
Just go bold with the considerations made in this doc section (yeah, I discovered afterwards that my idea wasn't that original): any class (or mixin) with own private members should be implicitly marked with the base modifier. As this modifier is infectious (i.e. it applies to all inheriting classes, be them direct or indirect descendants), the containing library's code will never get unpleasant surprises with objects passed from outside.
If the class in question is not exported (including private), no harm is done. If the class is exported, any implementation outside the containing library will turn into broken code and require refactoring, which is not trivial when the implementing class already extends some other class (than Object).
I have reviewed the discussion in #4348 and pondered for a solution to the problem of the two interfaces that a class with own private members has:
This flaw is what makes possible that code from the same library, reachable from outside (through exports), taking as input an object of the said class, may discover that the private members are missing from the received object because its type is simply an implementation the public interface.
Illustration (common knowledge)
The code above throws
NoSuchMethodError.Off topic, can anyone explain why the code works and prints
Doing stuff in IIif the comment delimiters aroundextends IIare removed? 🤨 Is the compiler happy with any implementation of the private method_do(), as long as it originates from the same library, namey the totally unrelated classII❓Proposal
Just go bold with the considerations made in this doc section (yeah, I discovered afterwards that my idea wasn't that original): any class (or mixin) with own private members should be implicitly marked with the
basemodifier. As this modifier is infectious (i.e. it applies to all inheriting classes, be them direct or indirect descendants), the containing library's code will never get unpleasant surprises with objects passed from outside.If the class in question is not exported (including private), no harm is done. If the class is exported, any implementation outside the containing library will turn into broken code and require refactoring, which is not trivial when the implementing class already extends some other class (than
Object).