dart-lang / dart-lang/language

Infer the return type of a cycle-free arrow getter

Open
#3,222 12 comments 6 reactions 0 assignees View on GitHub
feature
Dominant language
TeX
Stars
2.9k
Forks
239
Avg merge
2d 18h
Merged PRs (30d)
14

Description

Cf. [this comment](https://github.com/dart-lang/language/issues/395#issuecomment-1639762517).

Type inference is applied to non-local variable declarations. For instance:

```dart
var x = 10;

void main() {
x = true; // Error, because `x` has the inferred declared type `int`.
}
```

Type inference fails and causes a compile-time error in the case where it involves circular dependencies, even in cases where those dependencies do not give rise to non-termination of the initialization step:

```dart
// Circular dependency error.
var x = () { print(y); return 1; } ();
var y = () { print(x); };
```

Interestingly, a variant of this program that makes `x` a getter is accepted:

```dart
get x { print(y); return 1; }
var y = () { print(x); };

void main() {
print('$x, $y'); // Terminates.
}
```

Presumably, this choice was made because getters are assumed to give rise to general computation, and hence it is a futile exercise to try to show that non-termination is guaranteed or even likely.

The other notable difference is that `get x` has return type `dynamic`, because no attempt is made to infer the return type of a getter.

As @roblframpton mentions in https://github.com/dart-lang/language/issues/395, this difference seems to have a rather tenuous motivation. In particular, there is no apparent difference between the complexity associated with type inference of a getter of the form `get x => e;` and a variable declaration of the form `late final x = e;`.

We could make the choice to perform the same cyclicity analysis on getter declarations as the analysis that we currently use on non-local variable declarations, and infer the return type of a getter in the case where no cycles were detected.

For getter declarations with cyclic dependencies we could (1) report a compile-time error and ask the developer to write the return type explicitly, or (2) use `dynamic` (same as today). The former option would be helpful for anyone who wants to avoid `dynamic` in the signatures of widely available declarations, and the latter option would be less breaking in software where many getters have return type `dynamic` because no return type was declared.

This proposal should not make Dart software less statically typed than it would otherwise be, even in the case where we choose option (2): Some getters with no declared return type would now have a non-`dynamic` return type, and other getters would keep the same return type (which is `dynamic`). Also, we will presumably continue to help developers who wish to avoid the type `dynamic` in their APIs (`strict-inference: true` in 'analysis_options.yaml' will do).

@dart-lang/language-team, WDYT? Is there a good reason why we shouldn't perform type inference on non-recursive getters with no declared return type?

Contributor guide

Open the contributing guide

Research direction

Start with the linked comment and Dart language issue 395 to understand the existing inference rules for non-local variables and getters. Compare the proposed cycle analysis with the current behavior described in the examples. Done requires an agreed design for recursive and cycle-free getters, including whether cyclic cases report an error or retain dynamic.

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
Mostly clear
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.