flutter / flutter

Flutter makes it easy and fast to build beautiful apps for mobile and beyond
https://flutter.dev
BSD 3-Clause "New" or "Revised" License
165.22k stars 27.26k forks source link

FutureBuilder<T> in Flutter version 1.22.0-10.0.pre.221 is flawed #65999

Closed airxnoor closed 4 years ago

airxnoor commented 4 years ago

Hi,

The recent changes to add nullability support has caused FutureBuilder<T> to be unusable. Consider this code snippet:

late final Future<SomeModel?> _future;

void initState() {
  _future = _prepareFuture();
}

Widget build() {
  return FutureBuilder<SomeModel>(
    future: _future,
    ...
  );
}

It's not possible to use the above code anymore as Dart Analyzer screams about error: The argument type 'Future<SomeModel?>' can't be assigned to the parameter type 'Future<SomeModel>?'

Now, if you change the FutureBuilder to read FutureBuilder<SomeModel?> instead, then you get another error: error: 'SomeModel?' doesn't extend 'Object'.

My gut feeling: recent changes made to FutureBuilder introduced a typo:

Current FutureBuilder property in async.dart:

final Future<T>? future;

I think this should instead be defined as:

final Future<T?> future;
pedromassangocode commented 4 years ago

Hi @airthings-noordawod Can you please provide your flutter doctor -v and a minimal complete reproducible code sample? Thank you

airxnoor commented 4 years ago

Sure thing.

flutter doctor -v ``` $ flutter doctor -v [✓] Flutter (Channel master, 1.22.0-10.0.pre.221, on Mac OS X 10.15.6 19G2021 x86_64, locale en-NO) • Flutter version 1.22.0-10.0.pre.221 at /Users/noor/Library/Google/Flutter • Framework revision fa646339d6 (6 hours ago), 2020-09-16 17:47:04 -0700 • Engine revision 933f811d94 • Dart version 2.10.0 (build 2.10.0-135.0.dev) [✓] Android toolchain - develop for Android devices (Android SDK version 29.0.2) • Android SDK at /Users/noor/Library/Google/AndroidSDK • Platform android-29, build-tools 29.0.2 • ANDROID_HOME = /Users/noor/Library/Google/AndroidSDK • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6222593) • All Android licenses accepted. [✓] Xcode - develop for iOS and macOS (Xcode 11.7) • Xcode at /Applications/Xcode.app/Contents/Developer • Xcode 11.7, Build version 11E801a • CocoaPods version 1.8.4 [✓] Chrome - develop for the web • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome [✓] Android Studio (version 4.0) • Android Studio at /Applications/Android Studio.app/Contents • Flutter plugin version 48.1.2 • Dart plugin version 193.7547 • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6222593) [✓] IntelliJ IDEA Ultimate Edition (version 2020.2.1) • IntelliJ at /Applications/IntelliJ IDEA.app • Flutter plugin version 49.0.4 • Dart plugin version 202.7206 [✓] Connected device (4 available) • Pixel 3a (mobile) • XXXXXXXXX • android-arm64 • Android 10 (API 29) • Doro 8035 (mobile) • XXXXXXXXX • android-arm • Android 7.1.2 (API 25) • Web Server (web) • web-server • web-javascript • Flutter Tools • Chrome (web) • chrome • web-javascript • Google Chrome 85.0.4183.102 • No issues found! ```

Complete working example No.1:

code 1 ```dart import 'dart:math' as math; import 'package:flutter/material.dart'; void main() { runApp(FutureTestWidget()); } class FutureTestWidget extends StatefulWidget { final random = math.Random.secure(); @override State createState() => _FutureTestWidgetState(); } class _FutureTestWidgetState extends State { late final Future _future; @override void initState() { super.initState(); // A future that may or may not return a String, based on a random boolean evaluation. _future = Future.delayed( const Duration(seconds: 3), () => widget.random.nextBool() ? '${DateTime.now().millisecondsSinceEpoch}' : null, ); } @override Widget build(BuildContext context) => MaterialApp( home: FutureBuilder( future: _future, builder: (context, snapshot) { return Center(child: Text('Future evaluates to: "${snapshot.data}"'),) }, ), ); } ```

This demonstrates the problem with having a _future variable that may or may not return a value of type String. The error reported by Dart Analyzer in this case: The argument type 'Future<String?>' can't be assigned to the parameter type 'Future<String>?'.

--

Complete working example No.2:

code 2 ```dart import 'dart:math' as math; import 'package:flutter/material.dart'; void main() { runApp(FutureTestWidget()); } class FutureTestWidget extends StatefulWidget { final random = math.Random.secure(); @override State createState() => _FutureTestWidgetState(); } class _FutureTestWidgetState extends State { late final Future _future; @override void initState() { super.initState(); // A future that may or may not return a String, based on a random boolean evaluation. _future = Future.delayed( const Duration(seconds: 3), () => widget.random.nextBool() ? '${DateTime.now().millisecondsSinceEpoch}' : null, ); } @override Widget build(BuildContext context) => MaterialApp( home: FutureBuilder( future: _future, builder: (context, snapshot) { return Center(child: Text('Future evaluates to: "${snapshot.data}"'),) }, ), ); } ```

This demonstrates the problem with having a FutureBuilder of type String? (since the latter isn't a subtype of Object). The error reported by Dart Analyzer in this case: 'String?' doesn't extend 'Object'.

I hope these demonstrate the problem of (chicken and egg) :)

pedromassangocode commented 4 years ago

This is reproducible with latest master channel.

flutter doctor -v ``` [✓] Flutter (Channel master, 1.22.0-10.0.pre.221, on Mac OS X 10.15.6 19G2021 x86_64, locale en) • Flutter version 1.22.0-10.0.pre.221 at /Users/pedromassango/dev/SDKs/flutter_master • Framework revision fa646339d6 (11 hours ago), 2020-09-16 17:47:04 -0700 • Engine revision 933f811d94 • Dart version 2.10.0 (build 2.10.0-135.0.dev) [✓] Android toolchain - develop for Android devices (Android SDK version 30.0.1) • Android SDK at /Users/pedromassango/Library/Android/sdk • Platform android-30, build-tools 30.0.1 • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6222593) • All Android licenses accepted. [✓] Xcode - develop for iOS and macOS (Xcode 11.7) • Xcode at /Applications/Xcode.app/Contents/Developer • Xcode 11.7, Build version 11E801a • CocoaPods version 1.9.3 [✓] Chrome - develop for the web • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome [!] Android Studio (version 4.0) • Android Studio at /Applications/Android Studio.app/Contents ✗ Flutter plugin not installed; this adds Flutter specific functionality. ✗ Dart plugin not installed; this adds Dart specific functionality. • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6222593) [✓] IntelliJ IDEA Community Edition (version 2020.2.2) • IntelliJ at /Applications/IntelliJ IDEA CE.app • Flutter plugin version 49.0.4 • Dart plugin version 202.7319.5 [✓] VS Code (version 1.48.2) • VS Code at /Applications/Visual Studio Code.app/Contents • Flutter extension version 3.14.1 [✓] Connected device (4 available) • sdk gphone x86 arm (mobile) • emulator-5554 • android-x86 • Android 11 (API 30) (emulator) • macOS (desktop) • macos • darwin-x64 • Mac OS X 10.15.6 19G2021 x86_64 • Web Server (web) • web-server • web-javascript • Flutter Tools • Chrome (web) • chrome • web-javascript • Google Chrome 85.0.4183.102 ! Doctor found issues in 1 category. Process finished with exit code 0 ```
airxnoor commented 4 years ago

By the way, one more thing about the latest changes in async.dart:

Now it's not possible to use void as T, like in: FutureBuilder<void>.

Reported elsewhere for other parts of Flutter: https://github.com/flutter/flutter/issues/65938#issuecomment-693697508

airxnoor commented 4 years ago

In async.dart, there are few other places where the definition should be fixed (f.ex: StreamBuilderBase):

Current:

final Future<T>? future;

-OR-

final Stream<T>? stream;

To be changed to:

final Future<T?> future;

-AND-

final Stream<T?> stream;
github-actions[bot] commented 3 years ago

This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.