Description
The scope for class-like augmentations in the proposal for augmentations is inconsistent with the library scope for enhanced parts.
For enhanced parts, all files, parts or library, within the same library have simple name access to the entities declared in the library. This is motivated with the ability to seamlessly split a library into several parts without changing the semantics. For instance splitting
// foo.dart
method1() { method2(); }
method2() { method3(); }
method3() {}
into
// foo.dart
part 'bar.dart';
part 'baz.dart';
method3() {}
// bar.dart
part of 'foo.dart';
part 'boz.dart';
// boz.dart
part of 'bar.dart';
method1() { method2(); }
// baz.dart
part of 'foo.dart';
method2() { method3(); }
is valid since all files, foo.dart
, bar.dart
, baz.dart
, and boz.dart
have access to entities declared in any other files of the same library.
For class-like augmentations this isn't the case because it uses lexical scoping even when the class-like declaration is split into an introductory declaration and one or more augmenting declarations. This means that the splitting of a class-like declaration into several augmentations does not preserve semantics. For instance splitting:
// visitor.dart
class LargeVisitorImpl {
visitMember1(Member1 node) { helper(); }
visitMember2(Member2 node) { helper(); }
...
visitMember100(Member100 node) { helper(); }
visitStatement1(Statement1 node) { helper(); }
visitStatement2(Statement2 node) { helper(); }
...
visitStatement100(Statement100 node) { helper(); }
visitExpression1(Expression1 node) { helper(); }
visitExpression2(Expression2 node) { helper(); }
...
visitExpression100(Expression100 node) { helper(); }
static helper() {}
}
into
// visitor.dart
part 'member_visitor.dart';
part 'expression_visitor.dart';
part 'statement_visitor.dart';
class LargeVisitorImpl {
static helper() {}
}
// member_visitor.dart
part of 'visitor.dart';
augment class LargeVisitorImpl {
visitMember1(Member1 node) { helper(); }
visitMember2(Member2 node) { helper(); }
...
visitMember100(Member100 node) { helper(); }
}
// statement_visitor.dart
part of 'visitor.dart';
augment class LargeVisitorImpl {
visitStatement1(Statement1 node) { helper(); }
visitStatement2(Statement2 node) { helper(); }
...
visitStatement100(Statement100 node) { helper(); }
}
// expression_visitor.dart
part of 'visitor.dart';
augment class LargeVisitorImpl {
visitExpression1(Expression1 node) { helper(); }
visitExpression2(Expression2 node) { helper(); }
...
visitExpression100(Expression100 node) { helper(); }
}
results in compile time errors in all calls to helper();
which now have to be replaced with LargeVisitorImpl.helper();
in order to preserve semantics. This would even be the case if all augmentations were in the same file.
I find the two structures to be similar; 1) libraries split into a main library file and several part files, and 2) class-like declarations split into an introductory declaration and several augmenting declarations. They both a have shared responsibility of defining the respective name spaces and to me it therefore seems natural that they should also share the privilege of having simple name access to entities declared in that name space.