Skip to content

Commit 9769fc7

Browse files
authored
update how variable augmentations work (#3079)
Closes #3046. Partly resolves #3041. I altered the proposal to simply disallow augmenting getters and setters with variables. While this is potentially possible to specify, I think it is difficult to explain the behavior and wouldn't be intuitive. We can always add it back later.
1 parent 9e8895b commit 9769fc7

File tree

1 file changed

+70
-34
lines changed

1 file changed

+70
-34
lines changed

working/augmentation-libraries/feature-specification.md

Lines changed: 70 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Augmentation Libraries
22

33
4-
Version: 1.11 (see [Changelog](#Changelog) at end)
4+
Version: 1.12 (see [Changelog](#Changelog) at end)
55

66
Augmentation libraries allow splitting a Dart library into files. Unlike part
77
files, each augmentation has its [own imports][part imports] and top-level
@@ -316,9 +316,6 @@ augmented, but it follows generally the same rules as any normal identifier:
316316
initializer if the member being augmented is not a field with an
317317
initializer.
318318
319-
**TODO:** Define the behavior when a field is augmented by a getter or
320-
setter, and then later again by a field.
321-
322319
* **Augmenting functions**: When augmenting a function, `augment super` refers
323320
to the augmented function. Tear offs are allowed.
324321
@@ -441,12 +438,12 @@ this interact with type checking calls to the function?**
441438

442439
### Augmenting variables, getters, and setters
443440

444-
Augmentations on variables, getters, and setters are more complex because the
445-
language treats those as [mostly interchangeable][uniform]. We want to preserve
446-
that flexibility in augmentations. For example, an augmentation might want to
447-
wrap access to a variable in an augmenting getter. Or an augmentation may want
448-
to fill in the body of an unimplemented getter by using a backing variable
449-
declaration.
441+
While the language treats variables, getters, and setters as
442+
[mostly interchangeable][uniform], within augmentation libraries we do not allow
443+
augmenting getters and setters with variables. Since augmentations are tightly
444+
coupled to the libraries they augment, this restriction has minimal impact, and
445+
it does not greatly affect the ability of a library to change a field to a
446+
getter/setter pair or vice-versa.
450447

451448
[uniform]: https://en.wikipedia.org/wiki/Uniform_access_principle
452449

@@ -489,23 +486,53 @@ More specifically:
489486
non-final variable in the main library. Inside the augmenting setter, an
490487
`augment super =` expression invokes the original setter.
491488

492-
* **Augmenting a getter and/or setter with a variable:** A variable in an
493-
augmentation library can augment a getter in the main library. A non-final
494-
variable can augment a setter as well. The implicit getter and setter
495-
defined by the augmenting variable replace the getter and setter in the main
496-
library.
497-
498-
* **Augmenting a variable with a variable:** The original storage location is
499-
discarded and the original implicit getter and setter are replaced with the
500-
new implicit ones. *In most cases, the distinction of which implicit
501-
getter/setter is kept is not visible. But if augmenting a `late` variable
502-
with a non-`late` one or vice versa, the bodies behave differently in
503-
user-visible ways.*
504-
505-
The original initializer expression is replaced with the augmenting
506-
variable's initializer if it has one. The augmenting initializer may use an
489+
* **Augmenting a getter and/or setter with a variable:** This is a
490+
compile-time error in all cases. We may decide in the future to allow
491+
augmenting abstract or external getters and setters with variables, but for
492+
now you can instead use the following workaround:
493+
494+
- Add a new field.
495+
- Augment the getter and/or setter to delegate to that field.
496+
497+
If a concrete variable is augmented by a getter or setter, you **can** still
498+
augment the variable, as you are only augmenting the initializer. This is
499+
not considered to be augmenting the augmenting getter or setter, since those
500+
are not actually altered.
501+
502+
The reason for this is that whether a member declaration is a field versus a
503+
getter/setter is a visible property of the declaration: It determines
504+
whether the member can be initialized in a constructor initializer list. It
505+
is also a visible distinction when introspecting on a program with the
506+
analyzer, macros, or mirrors.
507+
508+
When a declaration is augmented, we don't want the augmentation to be able
509+
to change any of the known properties of the existing member being
510+
augmented. For example, we don't allow you to augment a method with a getter
511+
that returns a function. Augmenting a getter/setter pair with a field would
512+
change the "can be used in a constructor initializer" property, so we forbid
513+
it. Augmenting a field with a getter/setter doesn't change that property so
514+
it is allowed.
515+
516+
* **Augmenting a variable with a variable:** When augmenting a variable with
517+
a variable, the behavior differs depending on whether the original variable
518+
has a concrete implementation or not. Note that this concrete implementation
519+
could be one that is filled in by a compiler or other external source, if
520+
the declaration is marked `external`.
521+
522+
If the variable being augmented _does not_ have a concrete implementation,
523+
then it gets one from the augmenting variable. This includes the backing
524+
store, the implicit getter and setter, as well as the initializer if
525+
present.
526+
527+
If the variable being augmented _does_**_ have a concrete implementation,
528+
then only the initializer has any meaning, and it replaces the original
529+
initializer. In this case the augmenting initializer may use an
507530
`augment super` expression which executes the original initializer
508-
expression when evaluated.
531+
expression when evaluated. Augmenting a concrete field with a field does not
532+
affect its backing store, getter, or setter.
533+
534+
The `late` property of a variable must always be consistent between the
535+
augmented variable and its augmenting variables.
509536

510537
If the variable declaration in the original library does not have a type
511538
annotation, then the type is inferred only using the original library's
@@ -519,6 +546,11 @@ It is a compile-time error if:
519546

520547
* The original and augmenting declarations do not have the same type.
521548

549+
* An augmenting declaration uses `augment super` when the original declaration
550+
has no concrete implementation. Note that all external declarations are
551+
assumed to have an implementation provided by another external source, and
552+
they will throw a runtime exception when called if not.
553+
522554
* An augmenting initializer uses `augment super` and the original declaration
523555
is not a variable with an initializer.
524556

@@ -529,11 +561,11 @@ It is a compile-time error if:
529561
* A non-final variable is augmented with a final variable. We don't want to
530562
leave the original setter in a weird state.
531563

532-
* A non-`late` augmenting instance variable initializer contains `augment
533-
super` and the variable being augmented is `late`. *Initializers for `late`
534-
instance variables have access to `this` while non-`late` variables do not.
535-
This means a `late` variable's initializer can't be called from a non-`late`
536-
variable's initializer.*
564+
* A `late` variable is augmented with a non-`late` variable.
565+
566+
* A non-`late` variable is augmented with a `late` variable.
567+
568+
* A concrete getter or setter are augmented by a variable.
537569

538570
### Augmenting enum values
539571

@@ -928,11 +960,15 @@ language and our tools.
928960

929961
## Changelog
930962

963+
## 1.12
964+
965+
* Update the behavior for variable augmentations.
966+
931967
## 1.11
932968

933-
* Alter and clarify the semantics around augmenting external declarations.
934-
* Allow non-abstract classes to have implictly abstract members which are
935-
implemented in an augmentation.
969+
* Alter and clarify the semantics around augmenting external declarations.
970+
* Allow non-abstract classes to have implictly abstract members which are
971+
implemented in an augmentation.
936972

937973
## 1.10
938974

0 commit comments

Comments
 (0)