Skip to content

Conversation

shihaohong
Copy link
Contributor

@shihaohong shihaohong commented Dec 3, 2020

Description

Implements a nullable version of the RestorableBool property, which is necessary for widgets like Checkbox where a null value when tristate is true.

Related Issues

#62916

Tests

I added the following tests:

  • Test coverage for RestorableBoolN

Checklist

Before you create this PR, confirm that it meets all requirements listed below by checking the relevant checkboxes ([x]). This will ensure a smooth and quick review process.

  • I read the Contributor Guide and followed the process outlined there for submitting PRs.
  • I signed the CLA.
  • I read and followed the Flutter Style Guide, including Features we expect every widget to implement.
  • I read the Tree Hygiene wiki page, which explains my responsibilities.
  • I updated/added relevant documentation (doc comments with ///).
  • All existing and new tests are passing.
  • The analyzer (flutter analyze --flutter-repo) does not report any problems on my PR.
  • I am willing to follow-up on review comments in a timely manner.

Breaking Change

Did any tests fail when you ran them? Please read Handling breaking changes.

@flutter-dashboard flutter-dashboard bot added the framework flutter/packages/flutter repository. See also f: labels. label Dec 3, 2020
@google-cla google-cla bot added the cla: yes label Dec 3, 2020
@skia-gold
Copy link

Gold has detected about 62 untriaged digest(s) on patchset 3.
View them at https://flutter-gold.skia.org/cl/github/71653

@skia-gold
Copy link

Gold has detected about 30 untriaged digest(s) on patchset 4.
View them at https://flutter-gold.skia.org/cl/github/71653

@skia-gold
Copy link

Gold has detected about 49 untriaged digest(s) on patchset 4.
View them at https://flutter-gold.skia.org/cl/github/71653

@shihaohong shihaohong changed the title RestorableBoolN [WIP] RestorableBoolN Dec 3, 2020
@shihaohong shihaohong changed the title [WIP] RestorableBoolN RestorableBoolN Dec 3, 2020
@shihaohong shihaohong changed the title RestorableBoolN [State Restoration] RestorableBoolN Dec 3, 2020
@shihaohong shihaohong requested a review from goderbauer December 6, 2020 13:57
@shihaohong shihaohong added the a: state restoration RestorationManager and related APIs label Dec 6, 2020
@@ -413,7 +413,7 @@ abstract class RestorableProperty<T> extends ChangeNotifier {
/// [RestorableProperty]. Whenever new restoration data has been provided to
/// the [RestorationMixin] the property is registered to, either this method
/// or [fromPrimitives] is called before [initWithValue] is invoked.
T createDefaultValue();
T? createDefaultValue();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the ? here and below? Wouldn't you just specify a nullable type for T, e.g. class Foo extends RestorableProperty<bool?> { ... }.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh, didn't realize that I could do that :)

@@ -125,7 +125,50 @@ abstract class RestorableValue<T> extends RestorableProperty<T> {

@mustCallSuper
@override
void initWithValue(T value) {
void initWithValue(T? value) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same question as above, if this needs to be nullable, wouldn't you just specify T as something nullable?

@@ -185,6 +228,35 @@ class _RestorablePrimitiveValue<T extends Object> extends RestorableValue<T> {
}
}

// _RestorablePrimitiveValueN and its subclasses allows null values.
class _RestorablePrimitiveValueN<T extends Object> extends RestorableValueN<T> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe you can revert all changes you made to widgets/restoration.dart and above this line in this file by just changing this line to:

Suggested change
class _RestorablePrimitiveValueN<T extends Object> extends RestorableValueN<T> {
class _RestorablePrimitiveValueN<T extends Object?> extends RestorableValue<T> {

The Object? ensures that T can be null, if necessary.

After you do that, a lot of ? below in this file can also be removed, I think.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(With that in place, _RestorablePrimitiveValue can probably share some implementation with _RestorablePrimitiveValueN by just making _RestorablePrimitiveValue extend _RestorablePrimitiveValueN.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

@@ -185,6 +228,35 @@ class _RestorablePrimitiveValue<T extends Object> extends RestorableValue<T> {
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you also update the comment above _RestorablePrimitiveValue that explains how we could introduce nullable versions and make it point to _RestorablePrimitiveValueN?

assert(debugIsSerializableForRestoration(_defaultValue)),
// _RestorablePrimitiveValueN and its subclasses allows for null values.
// See [_RestorablePrimitiveValue] for the non-nullable version of this class.
class _RestorablePrimitiveValueN<T extends Object?> extends RestorableValue<T> {
Copy link
Contributor Author

@shihaohong shihaohong Dec 15, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just for my own understanding, the only reason with it is <T extends Object> here instead of just <T> is because toPrimitives returns an Object and the generic property value has to be at least a subclass of Object?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this just makes it explicit that T may be nullable.

// anticipation of NNBD (non-nullability by default).
class _RestorablePrimitiveValue<T extends Object> extends _RestorablePrimitiveValueN<T> {
_RestorablePrimitiveValue(T _defaultValue)
: assert(_defaultValue != null),
Copy link
Contributor Author

@shihaohong shihaohong Dec 15, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are the asserts here necessary, since non-nullability is baked into the subclass? One wouldn't be able to instantiate a _RestorablePrimitiveValue with null passed in to begin with. Then, the class would simply be:

// _RestorablePrimitiveValue and its subclasses do not allow null values in
// anticipation of NNBD (non-nullability by default).
class _RestorablePrimitiveValue<T extends Object> extends _RestorablePrimitiveValueN<T> {
  _RestorablePrimitiveValue(T _defaultValue) : super(_defaultValue);
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, I guess I can't think of a way to write a test for this to prevent a regression if someone were to make it nullable by accident, so the asserts act as sort of a line of defense?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Eventually, we can remove these asserts. For now we are keeping them for people who are not running their app with null-safety enabled.

Comment on lines 171 to 172
// _RestorablePrimitiveValueN and its subclasses allows for null values.
// See [_RestorablePrimitiveValue] for the non-nullable version of this class.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this comment was accidentally copied unchanged from _RestorablePrimitiveValueN. Maybe update it to reflect that _RestorablePrimitiveValue and subclasses are non-nullable and link to _RestorablePrimitiveValueN for the nullable version?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry about that, the way that GitHub shows the diffs for this change and how similar the names of both classes were made me really confused, so I ran into some weird hiccups

assert(value != null);
super.value = value;
}

@override
T fromPrimitives(Object? serialized) {
assert(serialized != null);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

replace the line below this one with return super. fromPrimitives(serialized)?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same in toPrimitives: just call super.toPrimitives after the assert?

/// A [RestorableProperty] that knows how to store and restore a [bool] that is
/// nullable.
///
/// {@macro flutter.widgets.RestorableNum}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a "see also" section linking to the non-nullable version?

Similarly, add the same section to RestorableBool to link to this one?

// anticipation of NNBD (non-nullability by default).
class _RestorablePrimitiveValue<T extends Object> extends _RestorablePrimitiveValueN<T> {
_RestorablePrimitiveValue(T _defaultValue)
: assert(_defaultValue != null),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Eventually, we can remove these asserts. For now we are keeping them for people who are not running their app with null-safety enabled.

assert(debugIsSerializableForRestoration(_defaultValue)),
// _RestorablePrimitiveValueN and its subclasses allows for null values.
// See [_RestorablePrimitiveValue] for the non-nullable version of this class.
class _RestorablePrimitiveValueN<T extends Object?> extends RestorableValue<T> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this just makes it explicit that T may be nullable.

Copy link
Member

@goderbauer goderbauer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@fluttergithubbot fluttergithubbot merged commit 2eee5ae into flutter:master Dec 16, 2020
@shihaohong shihaohong deleted the restorable-bool-n branch January 6, 2021 04:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
a: state restoration RestorationManager and related APIs framework flutter/packages/flutter repository. See also f: labels.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants