dart-lang / dart-lang/language

Allow the type of an object pattern to be inferred when specified as `_`

Open
#4,124 47 comments 17 reactions 0 assignees View on GitHub
patterns small-feature
Dominant language
TeX
Stars
2.9k
Forks
239
Avg merge
2d 18h
Merged PRs (30d)
14

Description

Ideas similar to this one have been discussed already when patterns were introduced, but I don't think there's an issue where the proposal has been presented in a concrete form.

We could make object patterns a bit more concise and convenient by using a wildcard `_` to indicate the type of the object pattern when it can be inferred:

```dart
class const PairClassWithATerriblyLongName(int x, int y);

void main() {
var pair = PairClassWithATerriblyLongName(2, 3);

// Using the proposed feature:
var number = switch (pair) {
_(x: >= 0, y: >= 0) => 'first',
_(x: < 0, y: >= 0) => 'second',
_(x: < 0, y: < 0) => 'third',
_(x: >= 0, y: < 0) => 'fourth',
};

// Compare this to the current syntax:
number = switch (pair) {
PairClassWithATerriblyLongName(x: >= 0, y: >= 0) => 'first',
PairClassWithATerriblyLongName(x: < 0, y: >= 0) => 'second',
PairClassWithATerriblyLongName(x: < 0, y: < 0) => 'third',
PairClassWithATerriblyLongName(x: >= 0, y: < 0) => 'fourth',
};

print('Found a pair in the $number quadrant');
}
```

(I'm assuming that we have [primary constructors](https://github.com/dart-lang/language/blob/main/working/2364%20-%20primary%20constructors/feature-specification.md), hopefully we will have them soon.)

It might be claimed that `_` causes the code to be less readable than it would have been with the explicit type. However, it's worth noting that when the `_` occurs repeatedly at the top level in cases like the above example then it is easy to see that every `_` stands for the same type, and it must be the static type of the scrutinee. Similarly, when `_` is used in a nested object pattern, e.g., `PairClassWithATerriblyLongName(x: _(isEven: true))`, the type of the nested object pattern could be rather easy to determine based on the enclosing patterns.

In any case, it will be a matter of style whether `_` is an acceptably readable type on any given object pattern, and individual organizations and developers will choose a style for this, just like they are choosing a style for many other things.

The inferred type of an object pattern may include actual type arguments:

```dart
class MyClass {
final X x;
MyClass(this.x);
}

void main() {
var xs = MyClass(1); // Inferred as `MyClass(1)`.
switch (xs) {
case MyClass(x: var y) when y.isEven:
print('Got an A!');
}
}
```

In the object pattern `Myclass(x: var y)`, the type argument `int` is inferred. We can see that it is actually `int` because `y.isEven` is accepted with no errors, and also because `y.isEven` is an error when we have `MyClass(x: var y)`. We can also see that the inferred type isn't `dynamic`, because `y.unknownMember` is an error.

This should all work the same when we use the proposed feature:

```dart
void main() {
var xs = MyClass(1); // Inferred as `MyClass(1)`.
switch (xs) {
case _(x: var y) when y.isEven:
print('Got an A!');
}
}
```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.