dart-lang / dart-lang/language
[Field Promotion] Promotion of fields on final classes
- Dominant language
- TeX
- Stars
- 2.9k
- Forks
- 239
- Avg merge
- 2d 18h
- Merged PRs (30d)
- 14
Description
With the new class modifiers feature, we have the ability express classes for which all subtypes are restricted to the same library as the defining class. This provides a path to defining a sound version of field promotion in which `final fields` on instances of `final` (or `sealed`) classes could be subject to promotion. This issue is for discussing the tradeoffs involved.
## Reasons not to do this
Several objections have been raised to this proposal, summarized here.
### Removing the `final` modifier becomes a breaking change
Currently, it is not a breaking change to remove the `final` modifier from a class. Allowing promotion on fields of final classes would change this - if the class had any public `final` fields, removing `final` from the class breaks downstream clients. For `sealed`, it is already very breaking to remove the modifier: however since `sealed` classes are abstract, they are mostly only useful through their non-`sealed` subclasses which just pushes the issue off.
### Changing a final field to a getter (and vice versa) becomes a breaking change.
Currently in Dart it is not a breaking change to switch between a `final` field and a getter. This field/getter symmetry is valued by many Dart programmers. Allowing promotion of final fields would break this, since changing a final field on a final class would break any clients using promotion. Moving in the other direction (getter to field) is also in principle breaking, since in more limited cases it can be breaking to do promotion where it was not previously done.
Note that this does not just apply to fields defined in final classes. For any public class except one marked `interface`, moving between a field and a getter would be breaking:
- For a final class, doing so changes promotion behavior directly
- For a base or simple class, there may be unknown final classes which inherit from the class and expose the member to promotion
## Options for addressing the concerns above
### Local promotion only
We could allow promotion only for uses of final fields on final classes within the same library as the definition of the class. We'd also need to restrict this to fields which are themselves declared in the same library as the class (rather than inherited) to avoid implicitly promoting a field from another library.
~~Note that it's not clear that we would want to restrict ourselves to final classes in this case: there's no real reason not to do this for all classes.~~ [Edit: as pointed out below, this doesn't work of course because of overrides]
### Explicit opt in at the field declaration
Use some kind of syntax at the definition site of the field (e.g. something like [stable getters](https://github.com/dart-lang/language/issues/1518)) to mark fields which are intended to be promoted
cc @dart-lang/language-team @mraleph
Contributor guide
Research direction
Start by reading the full discussion in issue #3050, including the linked stable getters proposal at dart-lang/language#1518. Compare the local-promotion and explicit-opt-in options and review the stated breaking-change concerns. No implementation files, tests, or agreed outcome are named, so completion would require design consensus before coding.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- dart
- Domain
- compilers
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 20/100