dart-lang / dart-lang/language

Type inference defaulting to dynamic can cause hard to find issues

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

Description

This is my first post here, apologies if I'm not correctly following protocol. I've run into an issue that is caused by Dart's silent defaulting to `dynamic` if type inference doesn't find a concrete type. Consider the following code:

```dart
Type typeOf() => T;

class Value extends InheritedWidget {
final T value;

Value({this.value, Widget child}) : super(child: child);

@override bool updateShouldNotify(_) => true;

static T of(BuildContext context) {
final type = typeOf>();
final provider = context.inheritFromWidgetOfExactType(type) as Value;
return provider.value; // <-- (1)
}
}

class StatefulValue extends StatefulWidget {
final T Function(BuildContext) valueBuilder;
final Widget child;

StatefulValue({this.valueBuilder, this.child}) : super();

@override createState() => _StatefulValueState(); // <-- (2)
}

class _StatefulValueState extends State> {
T _value;

@override initState() {
super.initState();
_value = widget.valueBuilder(context);
}

@override build(context) => Value(value: _value, child: widget.child);
}
```

This is then used like so:

```dart
class HomePage extends StatelessWidget {
@override build(context) => StatefulValue(
valueBuilder: (_) => 'Hello!',
child: Builder(
builder: (context) => Scaffold(
appBar: AppBar(
title: Text(Value.of(context)),
),
),
),
);
}
```

The details of the example don't matter, it just aims to demonstrate a subtle bug that's hidden within typical "Flutter noise": The code compiles without warnings, but instead of showing the expected 'Hello!' Text in the app bar, a runtime error is thrown: `"The getter 'value' was called on null."` (see `(1)`).

It took me quite a while to find the fix (see `(2)`):

```dart
@override createState() => _StatefulValueState();
```

In hindsight it makes perfect sense: without the `` annotation, Dart defaults to `_StatefulValueState`. An easily made mistake that creates a cascade of issues that's very hard to backtrack. In fact, now that I'm aware of this, I'm not at all sure I haven't made similar mistakes elsewhere that just haven't surfaced as bugs yet.

Testing surely helps, but I wonder if the Dart languge itself could be more helpful in such cases: If the analyzer fails to infer a concrete type, that's probably because I did something wrong unintentionally, and I surely would benefit from knowing about it. I wonder, would a compiler warning (or even a compile-time error) be feasible?

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.