spebbe / dartz

Functional programming in Dart
MIT License
756 stars 59 forks source link

Dart 2.0 compatible release? #7

Closed rich-j closed 6 years ago

rich-j commented 6 years ago

Google has just released Flutter Release Preview 1 and Dart Angular 5.0.0-beta (i.e. release candidate). They have the milestone for Dart2Stable as "Due by July 10, 2018".

Any timeframe for a Dart 2.0 compatible release of dartz?

Upgrading to Dart VM version: 2.0.0-dev.66.0 (Fri Jun 29 11:19:05 2018 +0200) on "macos_x64" now causes failures when running unit tests under the VM (Google recently made Dart 2.0 the default for the VM).

We are using your ddc_compat branch and still run fine under DDC. Here are the errors that now cause all unit tests to fail when run in the VM:

Unable to spawn isolate: file:///Users/richj/.pub-cache/git/dartz-dab47747ddffe55cafdddabba181c40bcbbb2de7/lib/src/ilist.dart:156:36: Error: The parameter 'l2' of the method 'IList::plus' has type dartz::IList<dartz::IList::A>, which does not match the corresponding type in the overridden method (dartz::IList<dynamic>).
Change to a supertype of dartz::IList<dynamic> (or, for a covariant parameter, a subtype).
  @override IList<A> plus(IList<A> l2) => foldRight(l2, (e, p) => new Cons(e, p));
                                   ^
file:///Users/richj/.pub-cache/git/dartz-dab47747ddffe55cafdddabba181c40bcbbb2de7/lib/src/list.dart:11:37: Error: The parameter 'f1' of the method 'ListTraversableMonadPlus::plus' has type dart.core::List<dartz::ListTraversableMonadPlus::plus::A>, which does not match the corresponding type in the overridden method (dart.core::List<dynamic>).
Change to a supertype of dart.core::List<dynamic> (or, for a covariant parameter, a subtype).
  @override List<A> plus<A>(List<A> f1, List<A> f2) => new List.from(f1)..addAll(f2);
                                    ^
file:///Users/richj/.pub-cache/git/dartz-dab47747ddffe55cafdddabba181c40bcbbb2de7/lib/src/list.dart:11:49: Error: The parameter 'f2' of the method 'ListTraversableMonadPlus::plus' has type dart.core::List<dartz::ListTraversableMonadPlus::plus::A>, which does not match the corresponding type in the overridden method (dart.core::List<dynamic>).
Change to a supertype of dart.core::List<dynamic> (or, for a covariant parameter, a subtype).
  @override List<A> plus<A>(List<A> f1, List<A> f2) => new List.from(f1)..addAll(f2);
                                                ^
file:///Users/richj/.pub-cache/git/dartz-dab47747ddffe55cafdddabba181c40bcbbb2de7/lib/src/option.dart:23:38: Error: The parameter 'o2' of the method 'Option::plus' has type dartz::Option<dartz::Option::A>, which does not match the corresponding type in the overridden method (dartz::Option<dynamic>).
Change to a supertype of dartz::Option<dynamic> (or, for a covariant parameter, a subtype).
  @override Option<A> plus(Option<A> o2) => orElse(() => o2);
                                     ^
file:///Users/richj/.pub-cache/git/dartz-dab47747ddffe55cafdddabba181c40bcbbb2de7/lib/src/ivector.dart:44:40: Error: The parameter 'fa2' of the method 'IVector::plus' has type dartz::IVector<dartz::IVector::A>, which does not match the corresponding type in the overridden method (dartz::IVector<dynamic>).
Change to a supertype of dartz::IVector<dynamic> (or, for a covariant parameter, a subtype).
  @override IVector<A> plus(IVector<A> fa2) {

Thanks

spebbe commented 6 years ago

Hi @rich-j!

I've pushed some really strange workarounds on ddc_compat (although not really related to DDC), that hopefully get your tests to run again. I would be very interested in hearing if it works for you.

I don't fully understand neither the original error nor the fix :-) The change that fixes the errors you are seeing consists of explicitly adding the mixin PlusOps<F, A> to classes that already should have this same mixin transitively. This looks like a Dart bug, but I'm not sure...

Also, Conveyor and most practical uses of Traversable are completely broken on 2.0.0-dev.66.0 for now... :-(

These kinds of sudden changes in the type system/semantics of Dart 2.0, combined with the subtly different languages currently implemented by DDC/VM/dart2js/analyzer/etc are the main reasons why i can't really give a time frame for when a fully compatible release of dartz will be out.

Since 2.0.0-dev.66.0 seems to put the final nail in the coffin for faking higher-kinded types, it is becoming increasingly clear that the current "open" design (e.g. IList#traverse(...)) will have to be at least partially closed and restricted to working with a pre-defined set of type class instances (e.g. IList#traverseOption, IList#traverseFuture, etc.), which will break backwards compatibility and generally kind of sucks.

Sad summary: don't expect a stable 2.0-compatible release until after Dart 2.0 itself is stable, but do expect that future release to have somewhat reduced functionality and some breaking API changes.

Input/thoughts/PRs welcome!

rich-j commented 6 years ago

Thanks - your ddc_compat branch fixed the VM runtime issues.

I am able to once again run our unit tests against our common library. Since the VM now uses Dart 2.0 semantics almost a third of our tests were now failing. These failures were mostly simple typing issues with our test code. For example:

final expected = new IMap.fromIterables([0,1], [new IList.from([2,4]), new IList.from([1,3,5])], comparableOrder() );

inferred the type for expected as IMap<Comparable, IList<int>>. Adding an explicit type to comparableOrder<int>() gave us the correct type of IMap<int, IList<int>>. (the correct type was needed for the test's expect equality check. We have all tests are working again.

The change you needed to make sounds like some of our Dart frustration. We encountered a runtime bug where abstract ancestor properties needed to be respecified in descendants https://github.com/dart-lang/sdk/issues/33420.

So far, our use of dartz is mostly for the immutable "containers" - e.g. iList, iMap, Either, Option, ... I admit that I gave up on using traverse on types such as iList<Future<_>> - the type system just wasn't letting it happen. We are converting from a Typescript project so we can get by without the higher order functions at this time. Much of our coding "pain" is due to type issues and variance issues - I know this isn't news to you.

Given that Dart 2.0 will enforce strong types but have messed up variance and higher-kinded support, I understand that the first Dart 2.0 dartz release will not be able to be backwards compatible.

spebbe commented 6 years ago

Good to hear -- thanks for reporting!

The issue you linked to definitely smells like it could be related -- thanks!

I'll try adding a couple of "type frozen" traverseXYZ and sequenceXYZ and see how it turns out! It should add some sorely missing type safety, so maybe it will all be for the best in the end.