Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Monad[Future].>> behave strangely #1357

Closed
weihsiu opened this issue Sep 5, 2016 · 7 comments
Closed

Monad[Future].>> behave strangely #1357

weihsiu opened this issue Sep 5, 2016 · 7 comments

Comments

@weihsiu
Copy link

weihsiu commented Sep 5, 2016

i have the following code snippet
Future { Thread.sleep(1000); println(1) } >> Future { println(2) }
in scalaz, it prints "1" and then "2"
but in cats 0.7.2, it prints "2" and then "1".
i don't know if this behavior is intentional or not, but imo, not intuitive.
this snippet though
Future { Thread.sleep(1000); println(1) } >>= (_ => Future { println(2) })
prints "1" and then "2" in both scalaz and cats.

@ceedubs
Copy link
Contributor

ceedubs commented Sep 5, 2016

@weihsiu this is one of several places in which cats opts to take strict parameters while scalaz uses by-name parameters. Strict parameters have less overhead, so this decision was made for performance reasons (it can be a really big deal for things like Semigroup's combine when you are combining lots of elements). Future isn't referentially transparent since it immediately starts executing. So unlike with a referentially transparent type, you can't freely refactor between >> and >>= without changing the execution semantics of your code (the State tutorial talks a little bit about a similar situation).

If you want to reason about when your side effects will occur, you should probably use something like Task.

I'll leave this open for now, as we probably should provide some documentation about strictness in cats vs scalaz and probably also specifically about Future since so many people use it and run into these sorts of questions.

@weihsiu
Copy link
Author

weihsiu commented Sep 5, 2016

thanks for the quick response! i also wondered about the strictness of Semigroup's combine. now that i know the answer, at least i know it's not an oversight. about Future though, i know it's not perfect, but many libraries return Future as it's async result. fs2.Task is not a cats Monad by default. i made fs2.Task a cats monad without checking the laws but that worked with ">>" when i convert scala Futures to fs2 Tasks.

@mpilquist
Copy link
Member

This is a tangent, but you might find the fs2-cats project helpful.

@weihsiu
Copy link
Author

weihsiu commented Sep 5, 2016

thanks for the pointer! i was looking for just such a library before i wrote the task monad.

@fommil
Copy link

fommil commented May 1, 2017

I expected to find Monad[Future] to be in alleycats non/alleycats#46 but was surprised to find it in cats.

Shouldn't we either: a) move non-law abiding instances to alleycats or b) merge all of alleycats into cats. Doing both is very confusing and means there is no clear line in the.

Or is this going to be addressed by https://github.com/typelevel/cats-effect ? // @djspiewak

@johnynek
Copy link
Contributor

johnynek commented May 1, 2017

@fommil see some discussion around here:

#1059

and also: https://gist.github.com/non/4d1f49fe41e2f12c463ae075bf5d0f06

the consensus was that we could not see anywhere these items violated laws without using non-functions (e.g. things that throw).

This bug is actually that the caller assumed the side effects in apply were going to follow the laws of the monad, but cats makes no guarantees about that (since apply is not part of the Monad type-class. note, we are using .success to create Future).

So, we use Future is just like Id except the value will be available in the future.

What law is violated and why aren't the tests catching it?

@djspiewak
Copy link
Member

Yeah, I have to agree with @johnynek here. I don't know of any way of violating the monad laws using Future without using things that are themselves not referentially transparent. You can violate EffectLaws almost trivially with Future (in fact, you cannot implement a lawful Effect[Future] at all), but that's not really the question here.

@LukaJCB LukaJCB closed this as completed Jul 3, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants