Skip to content
This repository has been archived by the owner on May 24, 2023. It is now read-only.

null safety #52

Merged
merged 20 commits into from
Feb 25, 2021
Merged

null safety #52

merged 20 commits into from
Feb 25, 2021

Conversation

hovadur
Copy link
Contributor

@hovadur hovadur commented Jan 7, 2021

No description provided.

@hovadur
Copy link
Contributor Author

hovadur commented Jan 7, 2021

"Some checks haven’t completed yet" - because of dart 2.2 instead of dart 2.12

@simolus3
Copy link

simolus3 commented Feb 9, 2021

@hovadur Are you still working on this? If you want, you can give me write access to your fork and I'll fix the CI and the conflicts.

@hovadur
Copy link
Contributor Author

hovadur commented Feb 9, 2021

@hovadur Are you still working on this? If you want, you can give me write access to your fork and I'll fix the CI and the conflicts.

I'll fix it today

@hovadur
Copy link
Contributor Author

hovadur commented Feb 9, 2021

@hovadur Are you still working on this? If you want, you can give me write access to your fork and I'll fix the CI and the conflicts.

All checks have passed :)

@simolus3
Copy link

@kevmoo Sorry to bother you here, but could you please review and publish this if possible?

This is blocking build_resolvers, which in turn is blocking build_test. With a migrated graphs package, we can write and test builders with null-safety.

Copy link
Contributor

@kevmoo kevmoo left a comment

Choose a reason for hiding this comment

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

@natebosch – other thoughts?

pubspec.yaml Outdated Show resolved Hide resolved
pubspec.yaml Outdated Show resolved Hide resolved
lib/src/shortest_path.dart Outdated Show resolved Hide resolved
example/crawl_async_example.dart Outdated Show resolved Hide resolved
example/crawl_async_example.dart Outdated Show resolved Hide resolved
@@ -34,7 +34,7 @@ final _empty = Future<Null>.value(null);
/// have not completed. If the [edges] callback needs to be limited or throttled
/// that must be done by wrapping it before calling [crawlAsync].
Stream<V> crawlAsync<K, V>(Iterable<K> roots, FutureOr<V> Function(K) readNode,
FutureOr<Iterable<K>> Function(K, V) edges) {
FutureOr<Iterable<K>?> Function(K, V) edges) {
Copy link
Contributor

Choose a reason for hiding this comment

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

@natebosch I am a bit surprised we allow returning null here? should we retain that behavior?

Copy link
Contributor

Choose a reason for hiding this comment

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

No, I think we should restrict it - we previously allowed null and [] to mean the same thing, and there is no need to do that in a null safe world.

I'm on the fence about statically typing it as non-nullable, but dynamically allowing null to maintain backwards compatibility for opt-out code. Even with a major version bump it might be friendly to do so.

lib/src/shortest_path.dart Outdated Show resolved Hide resolved
@@ -24,12 +24,12 @@ import 'dart:collection';
///
/// If you supply one of [equals] or [hashCode], you should generally also to
/// supply the other.
List<T> shortestPath<T>(
List<T>? shortestPath<T>(
Copy link
Contributor

Choose a reason for hiding this comment

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

Should this be <T extends Object>? I don't know that null is ever useful value here... but maybe we don't want to be overly opinionated about it. There is an assert below that start is not null though.

Copy link
Contributor

Choose a reason for hiding this comment

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

My gut reaction is that most of these should be <T extends Object>, but I could also be convinced otherwise.

lib/src/shortest_path.dart Outdated Show resolved Hide resolved
lib/src/strongly_connected_components.dart Outdated Show resolved Hide resolved
lib/src/strongly_connected_components.dart Outdated Show resolved Hide resolved
lib/src/strongly_connected_components.dart Outdated Show resolved Hide resolved
lib/src/strongly_connected_components.dart Outdated Show resolved Hide resolved
lib/src/crawl_async.dart Outdated Show resolved Hide resolved
@natebosch
Copy link
Contributor

@hovadur - the closer I look at this the more I'm realizing there are some subtle choices to make that could have an outsized impact on usability and how the migration looks.

Sorry for the delays in reviews so far, and for any churn. I'd like to take some more time and consider a couple different options for this migration against existing usage.

In particular one thing I'd like to make sure we make the right decision on is whether the return type of the various edges callbacks should be nullable. We don't have a consistent approach to that today, and after the null safety release being consistent (or not) will be more apparent.

In crawlAsync and stronglyConnecteComponents we handle null with a fallback to an empty list:
https://github.com/dart-lang/graphs/blob/436bc21a9f88e38e2288dd063b7efacae5d30c4a/lib/src/crawl_async.dart#L72
https://github.com/dart-lang/graphs/blob/436bc21a9f88e38e2288dd063b7efacae5d30c4a/lib/src/strongly_connected_components.dart#L55

In shortestPath we try to disallow a null return:
https://github.com/dart-lang/graphs/blob/436bc21a9f88e38e2288dd063b7efacae5d30c4a/lib/src/shortest_path.dart#L108

My gut is that disallowing null return is the right thing to do for the null safety release, and I'm going to take a look at what the implications are for callsites in terms of usability and the effect on type inference in typical usage.
Disallowing null may mean more callsites need to do a trick like ?? const <Never>[] which looks tricky, but allowing null may mean hitting a very frequent null check.

@hovadur
Copy link
Contributor Author

hovadur commented Feb 20, 2021

@hovadur - the closer I look at this the more I'm realizing there are some subtle choices to make that could have an outsized impact on usability and how the migration looks.

Sorry for the delays in reviews so far, and for any churn. I'd like to take some more time and consider a couple different options for this migration against existing usage.

In particular one thing I'd like to make sure we make the right decision on is whether the return type of the various edges callbacks should be nullable. We don't have a consistent approach to that today, and after the null safety release being consistent (or not) will be more apparent.

In crawlAsync and stronglyConnecteComponents we handle null with a fallback to an empty list:
https://github.com/dart-lang/graphs/blob/436bc21a9f88e38e2288dd063b7efacae5d30c4a/lib/src/crawl_async.dart#L72

https://github.com/dart-lang/graphs/blob/436bc21a9f88e38e2288dd063b7efacae5d30c4a/lib/src/strongly_connected_components.dart#L55

In shortestPath we try to disallow a null return:
https://github.com/dart-lang/graphs/blob/436bc21a9f88e38e2288dd063b7efacae5d30c4a/lib/src/shortest_path.dart#L108

My gut is that disallowing null return is the right thing to do for the null safety release, and I'm going to take a look at what the implications are for callsites in terms of usability and the effect on type inference in typical usage.
Disallowing null may mean more callsites need to do a trick like ?? const <Never>[] which looks tricky, but allowing null may mean hitting a very frequent null check.

@hovadur - the closer I look at this the more I'm realizing there are some subtle choices to make that could have an outsized impact on usability and how the migration looks.

Sorry for the delays in reviews so far, and for any churn. I'd like to take some more time and consider a couple different options for this migration against existing usage.

In particular one thing I'd like to make sure we make the right decision on is whether the return type of the various edges callbacks should be nullable. We don't have a consistent approach to that today, and after the null safety release being consistent (or not) will be more apparent.

In crawlAsync and stronglyConnecteComponents we handle null with a fallback to an empty list:
https://github.com/dart-lang/graphs/blob/436bc21a9f88e38e2288dd063b7efacae5d30c4a/lib/src/crawl_async.dart#L72

https://github.com/dart-lang/graphs/blob/436bc21a9f88e38e2288dd063b7efacae5d30c4a/lib/src/strongly_connected_components.dart#L55

In shortestPath we try to disallow a null return:
https://github.com/dart-lang/graphs/blob/436bc21a9f88e38e2288dd063b7efacae5d30c4a/lib/src/shortest_path.dart#L108

My gut is that disallowing null return is the right thing to do for the null safety release, and I'm going to take a look at what the implications are for callsites in terms of usability and the effect on type inference in typical usage.
Disallowing null may mean more callsites need to do a trick like ?? const <Never>[] which looks tricky, but allowing null may mean hitting a very frequent null check.

done

- Go to `1.0.0-dev`.
- Add some `<Never>` on empty list literals to improve inference in some
  test usages. Code that migrates to null safety will likely need the
  same.
- Use a few local variables to allow flow analysis.
- Switch a `whereType` to a `!`
- Add more `extends Object` to the generics that we use as map keys. No
  usage where a `null` is used would be likely to be correct. Retain
  nullable values allowe din `crawlAsync`, but don't write as `V?` since
  the `V` can be nullable in usage.
- Remove comments about null arguments.
- Handle the merge of the tweaked `shortestPath`
- Clean up a stale lint violation and ignore.
- Don't use nullable arguments for `equals` callbacks. `null` is only
  ever equal to `null`.
- Remove tests around assertion errors for null arguments.
- [Prior nit fix] Rename `getValue` to `readEdges`.
@natebosch natebosch merged commit f69f5fd into dart-archive:master Feb 25, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Development

Successfully merging this pull request may close these issues.

6 participants