spebbe / dartz

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

Provide const constructors for "empty" - e.g. Option none and IList nil #9

Closed rich-j closed 4 years ago

rich-j commented 6 years ago

I would like to add default values to optional function parameters such as:

void process([Option<X> param = none()]) { ... }

This results in the error Default values of an optional parameter must be constant.

Enhancement request - add "const constructors" to dartz for simple "empty" values such as Option none and IList nil.

My current error prone workaround is to leave the default as null and use the "if null" operator ?? to replace the parameter param ?? none().

rich-j commented 6 years ago

I tried adding "const constructors" to dartz such as described by Stack Overflow issue How to write abstract class constructors so that it will be flexible for extending in sub classes but quickly ran into issues with mixins https://github.com/dart-lang/sdk/issues/29395 and https://github.com/dart-lang/sdk/issues/32223. It's never as straightforward as it should be...

spebbe commented 6 years ago

Good suggestion -- I've been wanting this as well, but haven't been able to get it to work under strong mode either. However, with the existing fake higher-kinded mixins being close to useless under Dart 2, I was thinking of killing them off anyway. This might get rid of the problem and allow const constructors for some of the types. I'm currently on vacation, but will have a look soon!

modulovalue commented 5 years ago

@spebbe did you get a chance to look into it?

spebbe commented 5 years ago

@modulovalue, i've been trying out a couple of solutions to this but got stuck deciding which path to follow. If I push a branch with my current favourite solution, would you, @rich-j and/or anyone else be willing to try it out and see if it looks ok to you?

One problem is that 'const' + type reification behaves strangely in certain situations, but it might be possible to work around or just learn to live with.

rich-j commented 5 years ago

I'm up for trying out your implementation. Though I admit that we've been trained to not push the Dart type system very hard - probably because the compiler always wins ;-)

spebbe commented 5 years ago

@rich-j, @modulovalue Cool! I've pushed the branch 0_9_0_wip_2, with some const support for IList, Option, Unit and some other types. There are plenty of other changes, including a couple of removals (mainly monad transformers) and a few things that aren't backwards compatible... Also, Conveyor kind of works on Dart 2 now! It is a work in progress though, so beware of bugs and/or incomplete functionality.

Good luck -- feedback, suggestions and/or PR:s are very welcome!

rich-j commented 5 years ago

Branch 0_9_0_wip_2 so far shows no issues with our code or tests. Plus we can now specify default values - yea!

void process([Option<X> param = const None()]) { ... }

One dart aspect that threw me was the need to specify the default value with a const keyword. Shouldn't dart know that it's const? It took me a little digging to find DON’T use const redundantly which specifies that:

Default values are not included in this list because future versions of Dart may support non-const default values.

Also I noted that we can't use the none() or nil() convenience functions to define const values because of the const rules.

For anyone that wants to try this pre-release just change the pubspec.yaml dependency to:

dartz:  #'^0.8.3'
  git:
    url: https://github.com/spebbe/dartz
    ref: 0_9_0_wip_2
spebbe commented 5 years ago

That's great @rich-j -- thanks for trying it out! I'll try to fill in the blanks so that this can be released properly, but it might be a couple of weeks away.

BTW, I tried declaring none() like Option<A> none<A>() => const None(); and it actually type checks! However, the return value will always have a runtime reified type of Option<Null> and then all hell breaks loose on DDC and friends. I assume this is a bug in the analyzer/compiler and that this shouldn't actually pass as valid code, but I'll file a ticket and see what happens.

modulovalue commented 5 years ago

@spebbe could you publish a version of dartz that contains the const updates on pub.dev? or maybe at least 0.9.0wip as a prerelease?

spebbe commented 5 years ago

@modulovalue, Yes! I don't know why I haven't done that earlier -- i'll publish a prelease tonight.

spebbe commented 5 years ago

Published 0.9.0-dev.1

spebbe commented 4 years ago

Hell just froze over! 0.9.0 is merged to master and released to pub.dev.

Musta-Pollo commented 1 year ago

I am curious if I miss something, but I cannot make const IList or Option as it's an abstract class.

Ilist<int> projectIds = const IList<int>() //It's a abstract class

rich-j commented 1 year ago

Correct, you can't create an instance of an abstract class. You need to create instances from the implementation classes. For Option constants use either None or Some. For IList use Nil for an empty list - note the Cons constructor is not const so you can't create a constant IList with data.

Ilist<int> projectIds = const Nil<int>();
Option<int> maybeId = const None<int>();
Musta-Pollo commented 1 year ago

Thank you ❤️ . That is precisely what I need.