dart-lang / dart-lang/language

[Field Promotion] Promotion of fields on final classes

Open
#3,050 4 comments 12 reactions 0 assignees View on GitHub
class-modifiers field-promotion
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.