Eliminating `nullOk` Parameters

Summary

This migration guide describes conversion of code that uses the nullOk parameter on multiple of static accessors and related accessors to use alternate APIs with nullable return values.

Context

Flutter has a common pattern of allowing lookup of some types of widgets (InheritedWidgets) using static member functions that are typically called of, and take a BuildContext.

Before non-nullability was the default, it was useful to have a toggle on these APIs that swapped between throwing an exception if the widget was not present in the widget tree and returning null if it was not found. It was useful, and wasn’t confusing, since every variable was nullable.

When non-nullability was made the default, it was then desirable to have the most commonly used APIs return a non-nullable value. This is because saying MediaQuery.of(context, nullOk: false) and then still requiring an ! operator or ? and a fallback value after that call felt awkward.

The nullOk parameter was a cheap form of providing a null safety toggle, which in the face of true language support for non-nullability, was then supplying redundant, and perhaps contradictory signals to the developer.

To solve this, the of accessors (and some related accessors that also used nullOk) were split into two calls: one that returned a non-nullable value and threw an exception when the sought-after widget was not present, and one that returned a nullable value that didn’t throw an exception, and returned null if the widget was not present.

The design document for this change is here: https://flutter.dev/go/eliminating-nullok-parameters

Description of change

The actual change modified these APIs to not have a nullOk parameter, and to return a non-nullable value:

  1. MediaQuery.of
  2. Navigator.of
  3. ScaffoldMessenger.of
  4. Scaffold.of
  5. Router.of
  6. Localizations.localeOf
  7. FocusTraversalOrder.of
  8. FocusTraversalGroup.of
  9. Focus.of
  10. Shortcuts.of
  11. Actions.handler
  12. Actions.find
  13. Actions.invoke
  14. AnimatedList.of
  15. SliverAnimatedList.of
  16. CupertinoDynamicColor.resolve
  17. CupertinoDynamicColor.resolveFrom
  18. CupertinoUserInterfaceLevel.of
  19. CupertinoTheme.brightnessOf
  20. CupertinoThemeData.resolveFrom
  21. NoDefaultCupertinoThemeData.resolveFrom
  22. CupertinoTextThemeData.resolveFrom
  23. MaterialBasedCupertinoThemeData.resolveFrom

And introduced these new APIs alongside those, to return a nullable value:

  1. MediaQuery.maybeOf
  2. Navigator.maybeOf
  3. ScaffoldMessenger.maybeOf
  4. Scaffold.maybeOf
  5. Router.maybeOf
  6. Localizations.maybeLocaleOf
  7. FocusTraversalOrder.maybeOf
  8. FocusTraversalGroup.maybeOf
  9. Focus.maybeOf
  10. Shortcuts.maybeOf
  11. Actions.maybeFind
  12. Actions.maybeInvoke
  13. AnimatedList.maybeOf
  14. SliverAnimatedList.maybeOf
  15. CupertinoDynamicColor.maybeResolve
  16. CupertinoUserInterfaceLevel.maybeOf
  17. CupertinoTheme.maybeBrightnessOf

Migration guide

In order to modify your code to use the new form of the APIs, convert all instances of calls that include nullOk = true as a parameter to use the maybe form of the API instead.

So this:

MediaQueryData? data = MediaQuery.of(context, nullOk: true);

becomes:

MediaQueryData? data = MediaQuery.maybeOf(context);

You will also need to modify all instances of calling the API with nullOk = false (often the default), to accept non-nullable return values, or remove any ! operators:

So either of:

MediaQueryData data = MediaQuery.of(context)!; // nullOk false by default.
MediaQueryData? data = MediaQuery.of(context); // nullOk false by default.

both become:

MediaQueryData data = MediaQuery.of(context); // No ! or ? operator here now.

The unnecessary_non_null_assertion analysis option can be quite helpful in finding the places where the ! operator should be removed, and the unnecessary_nullable_for_final_variable_declarations analysis option can be helpful in finding unnecessary question mark operators on final and const variables.

Timeline

Landed in version: 1.24.0
In stable release: not yet

References

API documentation:

Relevant issues:

Relevant PRs: