dart-lang / dart-lang/language

Awkward two-constructor necessity in extension type with validation

Open
#3,343 19 comments 2 reactions 0 assignees View on GitHub
extension-types-later
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

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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.