@@ -4,7 +4,7 @@ Author: Bob Nystrom, Lasse Nielsen
4
4
5
5
Status: Accepted
6
6
7
- Version 1.5
7
+ Version 1.6
8
8
9
9
Experiment flag: class-modifiers
10
10
@@ -514,9 +514,7 @@ Many combinations don't make sense:
514
514
* ` sealed ` types cannot be constructed so it's redundant to combine with
515
515
` abstract ` .
516
516
* ` sealed ` types cannot be extended or implemented, so it's redundant to
517
- combine with ` final ` .
518
- * ` sealed ` types cannot be extended so it contradicts ` base ` .
519
- * ` sealed ` types cannot be implemented, so it contradicts ` interface ` .
517
+ combine with ` final ` , ` base ` , or ` interface ` .
520
518
* ` sealed ` types cannot be mixed in outside of their library, so it
521
519
contradicts ` mixin ` on a class. * It's useful to allow ` sealed ` on a mixin
522
520
declaration because the mixin can be applied within the same library.
@@ -933,8 +931,139 @@ as a mixin. If the class defines a generative constructor or extends anything
933
931
other than ` Object ` , then it already cannot be used as a mixin and no change is
934
932
needed.
935
933
934
+ ## Implementation and documentation suggestions for usability
935
+
936
+ * This section is non-normative. It's a set of suggestions to implementation and
937
+ documentation teams to help ensure that the feature is easy for users to use and
938
+ discover.*
939
+
940
+ ### Errors, error recovery, and fixups
941
+
942
+ First of all, to the extent that it's reasonably feasible to do so, we should
943
+ try to make the parser understand that any time it sees a top level sequence of
944
+ any of the keywords ` sealed ` , ` abstract ` , ` final ` , ` interface ` , ` base ` , ` mixin ` ,
945
+ or ` class ` , the user is trying to declare something class-like or mixin-like,
946
+ even if they left out an important keyword, used conflicting keywords, or put
947
+ keywords in the wrong order. That way we can issue errors whose IDE fixups will
948
+ help the user clean up their class or mixin declaration, rather than just
949
+ ` unexpected { ` or something. For example, this should be recognized by the
950
+ parser as an attempt to make a mixin or class:
951
+
952
+ ``` dart
953
+ interface sealed C {
954
+ ...
955
+ }
956
+ ```
957
+
958
+ (The parser will obviously issue an error, but it should still fire the
959
+ appropriate events to allow the analyzer to create a ` ClassDeclaration ` AST
960
+ node, and it should analyze the things inside the curly braces as class
961
+ members).
962
+
963
+ If the keywords aren't in the proper order (` sealed ` /` abstract ` , then
964
+ ` final ` /` interface ` /` base ` , then ` mixin ` , then ` class ` ), or if a keyword was
965
+ repeated, the parser error should be on the first keyword token that's out of
966
+ order or repeated, and the fixup should offer to fix the order by sorting and
967
+ de-duplicating the keywords appropriately. So in the example above, the "wrong
968
+ order" error should be on the keyword ` sealed ` , and the fixup should change it
969
+ to ` sealed interface ` , which is still an error for other reasons, but is at
970
+ least in the right order now.
971
+
972
+ With order and duplication out of the way, that leaves 127 possible combinations
973
+ of the 7 keywords. The remaining error cases (and their associated IDE fixups)
974
+ are:
975
+
976
+ - Did you say both ` abstract ` and ` sealed ` ? Drop ` abstract ` ; it’s redundant.
977
+ Now there's only 95 possibilities.
978
+
979
+ - Did you say both ` interface ` and ` final ` ? Drop ` interface ` ; it’s redundant.
980
+ Now there's only 71 possibilities.
981
+
982
+ - Did you say both ` base ` and ` final ` ? Drop ` base ` ; it’s redundant. Now
983
+ there's only 59 possibilities.
984
+
985
+ - Did you say both ` interface ` and ` base ` ? Say ` final ` instead. Now there's
986
+ only 47 possibilities.
987
+
988
+ - Did you say neither ` mixin ` nor ` class ` ? You have to pick one or the other or
989
+ both. The fixup can probably safely assume you mean ` class ` . (Exception: if
990
+ you just said ` interface ` and no other keywords, you probably mean `abstract
991
+ class`). Now there's only 36 possibilities.
992
+
993
+ - Did you say both ` sealed ` and ` final ` ? Drop ` final ` ; it’s redundant. Now
994
+ there's only 33 possibilities.
995
+
996
+ - Did you say both ` sealed ` and ` base ` ? Drop ` base ` ; it’s redundant. Now
997
+ there's only 30 possibilities.
998
+
999
+ - Did you say both ` sealed ` and ` interface ` ? Drop ` interface ` ; it’s redundant.
1000
+ Now there's only 27 possibilities.
1001
+
1002
+ - Did you say both ` mixin ` and ` class ` , as well as one of the following
1003
+ keywords: ` sealed ` , ` interface ` , or ` final ` ? Drop ` class ` and replace
1004
+ ` extends M ` with ` with M ` wherever it appears in your library. Now there's
1005
+ only 22 possibilities.
1006
+
1007
+ - Did you say both ` abstract ` and ` mixin ` , but not ` class ` ? Drop ` abstract ` ;
1008
+ it’s redundant. Now we are down to the 18 permitted possibilities.
1009
+
1010
+ If we take this sort of approach, then users who don't love reading
1011
+ documentation will be able to just experimentally string together combinations
1012
+ of the keywords we've made available to them, and the errors and fixups will
1013
+ guide them to something valid, and then they can play around and see the effect.
1014
+
1015
+ ### Introducing the feature to users
1016
+
1017
+ If we assume that most users will have access to the IDE fixups noted above, it
1018
+ suggests that a nice way to introduce the feature to folks would be to gloss
1019
+ over what combinations are redundant or contradictory, and just tell them in
1020
+ plain English what each keyword does. Users who love reading documentation can
1021
+ read further and find out which combinations are prohibited; users who don't can
1022
+ just try them out, and the IDE will train them which combinations are valid over
1023
+ time. So the core of the feature becomes explainable in just seven lines, three
1024
+ of which are just restatements of things the user was already familiar with.
1025
+ Something like:
1026
+
1027
+ - ` sealed ` means "this type has a known set of direct subtypes, so switching on
1028
+ it will require the switch to be exhaustive".
1029
+
1030
+ - ` abstract ` means "this type can't be constructed directly", but you already
1031
+ knew that. It's only included in the list to help clarify that ` abstract ` is
1032
+ one of the seven keywords users should try combining together at the top of
1033
+ your declaration.
1034
+
1035
+ - ` interface ` means "this type can't be extended from outside this library".
1036
+
1037
+ - ` base ` means "this type can't be implemented from outside this library".
1038
+
1039
+ - ` final ` means "this type can neither be extended nor implemented from outside
1040
+ this library".
1041
+
1042
+ - ` mixin ` means "this type can be used in mixin-like ways, i.e. it can appear in
1043
+ the 'with' clause of other classes". Granted, this is kind of a circular
1044
+ definition, but this explanation is intended for programmers familiar with
1045
+ Dart 2.19, and they're already familiar with mixins.
1046
+
1047
+ - ` class ` means "this type can be used in class-like ways, i.e. it can be
1048
+ extended, or constructed, unless otherwise forbidden". Again, this is a
1049
+ circular definition, but our audience obviously already knows what classes
1050
+ are. Including it in the list helps make it clear that we're putting mixins
1051
+ and classes on equal footing, and helps clarify why ` mixin class ` is a
1052
+ reasonable thing.
1053
+
1054
+ (Note that this list is deliberately in the order required by the grammar).
1055
+
1056
+ Obviously there are plenty of details left out of this description. But
1057
+ hopefully it should be enough to get people started using the feature, and the
1058
+ errors and fixups would help keep them on the rails.
1059
+
936
1060
## Changelog
937
1061
1062
+ 1.6
1063
+
1064
+ - Add implementation suggestions about errors, error recovery, and fixups for
1065
+ class modifiers.
1066
+
938
1067
1.5
939
1068
940
1069
- Fix mixin application grammar to match prose where ` mixin ` can't be applied
0 commit comments