dart-lang / dart-lang/language
Awkward two-constructor necessity in extension type with validation
- Dominant language
- TeX
- Stars
- 2.9k
- Forks
- 239
- Avg merge
- 2d 18h
- Merged PRs (30d)
- 14
Description
IIUC, when I want to validate a representation object, I can do that in a constructor in an extension type. But a primary constructor doesn't have a body, so that must be done as a separate constructor. I _must_ declare two constructors then, and one of them _must not_ be usable. Here's an example:
```dart
extension type DegreesKelvin._(double degrees) {
DegreesKelvin(this.degrees) {
if (degrees < 0) throw ArgumentError('must be positive');
}
}
```
* It feels awkward that a very common use case (I would think), validation, would require this extra dance. I _must_ declare the primary constructor because that's how I specify the representation, and I _must_ declare another constructor which includes validation.
* Making the primary constructor private doesn't protect call sites within this library. Callers can still call `DegreesKelvin._` and side-step the validation.
### Possible solutions
#### Encourage validation through `isValid` instance methods
This is how the [example in the spec](https://github.com/dart-lang/language/blob/main/accepted/future-releases/extension-types/feature-specification.md#motivation) is written.
#### Declare primary constructor in body
@bwilkerson suggested a syntax like:
```dart
extension type DegreesKelvin {
primary DegreesKelvin(int degrees) {
if (degrees < 0) throw ArgumentError('must be positive');
}
}
```
The modifier `primary` is, at this point, only a signal for the compiler to see which constructor declares the representation type and representation field name.
#### No primary constructors; go back to declaring the single field explicitly, as in inline classes
Just what the heading says.
#### Allow a primary constructor to be "re-declared" / "re-defined" with a body
This would look like:
```dart
extension type DegreesKelvin(int degrees) {
DegreesKelvin(int degrees) {
if (degrees < 0) throw ArgumentError('must be positive');
}
}
```
You could say the primary constructor is _declared_ on the first line and _defined_ in the body of the extension type. You could put in requirements that the parameter static type and name are the same as in the declaration. You could put in a lint that reports if such a constructor doesn't have a body or initializers (can just be the declaration on the first line).
Contributor guide
Research direction
Start by reading the extension-types feature specification linked in the issue, then compare its constructor rules with the DegreesKelvin example. Review the proposed alternatives and the unresolved discussion to identify a decided direction; done would require an agreed language-design change, with corresponding specification updates.
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
- 25/100