-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
Deprecate Future instances #4182
Conversation
I reread both conversations, and am unconvinced we should churn code because some people have assumed behavior not backed by the laws. We're trying to use deprecation as a linter, when perhaps we should just provide a linter. |
I'm not sure how well a (necessarily external) linter will reach users. My understanding of the discussions is that the goal is less about linting old/existing uses vs discouraging new ones and generally improving communication about the known traps. FWIW I don't think its unreasonable if the instances should stay in Cats permanently, just retain the deprecation. I've never used the technique described here, but if The Scala.js project cares a lot about compatibility and they recently implemented a similar technique to discourage use of the default |
I think it is fair to assume "some people" are actually "most, if not all, Also, as I said on discord, what is the point of having the instances if we can't guarantee their behavior. IMHO, it is not a good UX for cats users to constantly tell them "ah yeah, we broke your code but, you know, it's your fault because you are using As @armanbilge said, the idea of the deprecation is mostly to be clear and loud that using Finally, I do think it is a good idea to eventually move the instances to alleycats, or, at least, remove them from the default implicit scope (as suggested by Gavin) so an explicit import is necessary.
I tested all the recommendations on the depreciation message using a small local project PS: I am all ears for suggestions to improve the deprecation warning. |
Execution order was never supported in the first place. Should we also never change the iteration order of an unordered collection, even if we could optimize the documented use cases? Cats has done heroic work over the years maintaining binary compatibility and laws through years of evolution. Adding the constraint that we maintain arbitrary undocumented, unlegislated behaviors is a worrisome precedent.
As a trainer of junior Scala engineers and a recovering Haskell developer, feature imports make me grumpy, too. I don't use |
Right, and I don't say we should. Actually, I am saying the opposite, that we simply can't guarantee any predictable behavior with Also, I am not even saying that cats should try to provide the previous behavior. I am saying that we don't even know if the current one won't change in the future with another change; that is what I meant with predictable. Thus, again, using |
I think a lot of this discussion turns on what a good UX is. IMO, the problem is there is no good choice. I have never really met a user that wants someone else to be paternal with them. They may exist, but I don't know them. Most take the view that functions like: e.g. So, here, the analogy is: Future is perfectly lawful if and only if you use it for pure concurrency, not for side-effects. Given a user wants to use Future with side effects, there is really no "good UX" with cats: we could:
Maybe we should take a tougher stand against anything unsafe, but I would question alleycats at all at that point. I personally would say: there is no solution to periodic complaints, they are going to happen no matter what, and I wouldn't make a change at this time (bias to stability in libraries). No matter what we do, there will be more complaints. I'm 👎 on this one. |
Given it seems you know many users, do you know anyone that uses EditAfter re-reading my comment that the last paragraph sounded combative, not my intention. Rather it was a sincere question, I know I have a bias and I want to confirm it.
Intention, alleycats explicitly state that their instances do not hold the laws. Again, I am not against telling users "this is not cats fault, you are doing something it doesn't support", contrary I am proposing we explicitly tell them that is the case from the very beginning. |
I don't think this discussion about side-effects at all. Because AFAICT the OP in #4176 is using Re-reading #2334 (comment), this comment strikes me:
Haven't the changes in #3960 exactly lost us that? For sure, you can still use |
yes, see my original comment almost 4 years ago: #2334 (comment) -- I think it is domain specific. If you are doing a CRUD app, that would possibly never come up. If you are building data aggregation systems it might come up somewhat regularly. I've also used So, I do know many different people who have used cats on a regular basis because we used cats at work at both of my two recent jobs and I know library authors that depend on cats, but everyone has their own experiences with seeing other people use cats, I guess. I also know people who traverse That's the part of the argument I find so strange: like, everything is fine if we move it to another package in this same repo because in that package we have warned you enough, but in this package, you can be forgiven for doing side-effects and expecting something). I am fairly sure we would tell someone who wrote a side-effect in a function they pass to |
What about trying to restore the original semantics of traversing a list of |
To be honest, yes; that is my whole argument. My point is just "cats can't guarantee consistent behavior, thus let's be clear about it".
Well, I personally don't think that is a fair comparison. Also, if the point is people will break the rules no matter what. Then, why alleycats exist? Why does cats-effect use the Even more, a common argument against the removal or movement of the instances is that cats have been doing an excellent job at being stable. But But, I think I am being repetitive here.
Not sure if possible, but I don't think is a good idea to impose the burden of ensuring |
We can't do that without ugly hacks. The change is in how traverse works in order to be type safe, and that change is in the |
I think the right answer to that is the same as rust's unsafe. It is not for things that are actually wrong, it is for when the compiler can't see it is safe, but the programmer can, e.g. // this function is totally safe *but the compiler can't see that*
def sortNonEmpty[A: Ordering](nel: NonEmptyList[A]): NonEmptyList[A] =
NonEmptyList.fromListUnsafe(nel.toList.sorted) So, I think the answer should be: we have unsafe things to signal to the user you need to prove some invariants yourself (either by checking at runtime, or maintaining them yourself with some other structure). So, I would push back on the mentality of "trying to discourage the user..." I feel like that direction is paternalism and it is hard to draw the line where that ends. For instance, I don't like people do write So, to me, that's the motivation of alleycats: where the law violations will not be observed because the caller has extra invariants in play that are not true in general. So, we could move I feel like here is the same thing: we prefer cats effect, but you may have some use cases for future instances here, but keep in mind that when programming with side-effects you can easily have subtle bugs, and good luck. |
Actually, thinking about this more there is a tension here. In I actually had a PR for an idea that allows the Applicative to control this: With that PR or something like it, the That said, even that is under-specified. It seems like what the user really wanted was Basically, if you are using I hear the people that say because of that we shouldn't have instances. I have laid out why I disagree with that view, but I doubt we will all agree. |
Sure. But then, why is a warning that says this is generally unsafe but if you are good then here is the way to silence it, much different than that?
With all due respect, your examples / comparisons are getting more and more out of line with each reply; you are not comparing something that can change the semantics of a program with code style. Also, I don't buy the whole "trying to discourage the user" / "paternalism" argument.
I would agree with that, but AFAIK (I could be totally wrong on this, I am not an expert on the internal of cats) we can't have a But, if that is possible I do think it would be a good idea to make that change. Finally, I personally don't feel anybody has provided real feedback about my proposal (recognizing that I wasn't clear about it until my previous reply). So I will try one last time. Do folks believe it is a good idea that cats is clearer and louder about it not guaranteeing the execution order and concurrent execution of Second part of the proposal (assuming you agree with the first part; being loud and clear).
|
I apologize if I have frustrated you, but despite you using the phrase "with all due respect" I feel like your replies to me have been pretty negative. I may have also bummed you out but when these discussions turn negative a likely outcome is we are both less likely to contribute and we all lose. Anyway, you have asked for feedback: my opinion is that we do nothing except tell people who use Future in an effectful way that it will likely cause bugs such as this one, and they should consider cats-effect (and maybe link to this talk: https://m.youtube.com/watch?v=qgfCmQ-2tW0 ) |
@johnynek question: in #2334 (comment) you said
This makes a lot of sense to me and AFAICT is the use-case for lawful |
I don't really have any guidance and I tried to think of why. I think the answer is there are basically only two functions to watch out for: Monadic constraints aren't generally a problem (usually in the impure case, but pretty much never in the pure case). The only issue, I think, is when you have |
Thank you for taking time to think about that. I found this answer to be very insightful about what's happening under-the-hood. So to close this out, going forward what exactly should we explain to users is the correct way to use
Then, if @BalmungSan is interested to continue we can make this into a docs PR. Thanks again. |
Can anyone think of other examples beyond I would simply say: any non-pure use of |
And just to be 100% clear (apologies, if you said it before and I missed it): you are 👎 on putting this in a deprecation message on these instances, even if we also promise that they will not be removed from Cats? I know you said:
But it wasn't obvious to me if a deprecation is a form of instability. This goes to your point about how
|
I don't think deprecation warnings are all that effective. If you see it, but want to keep using Future you have either junked someone's build, or got them to turn off some or all warnings. So basically only the people who say "oh, I can easily move to cats-effect" but somehow don't know that's a good idea. I think you are taxing one group to try to advertise to the other. I don't think it's great. Sadly, in all the industrial code bases I have seen they are PACKED with deprecation warnings. I just don't think they are effective. |
Ok, thanks. Ross also had reservations about using a deprecation here, so let's just focus on getting this messaging into the documentation. |
If cats should have not provided instances for
Future
is a never-ending discussion.However, I think the key points of such discussion are:
Thus, I propose (well, actually it was Gavin's idea :p) to deprecate them so that users are aware that their usage is not recommended.
And then move them to alleycats on the release of cats 3
This PR adds the deprecation and allows users to be prepared for the change.
Also, the deprecation message includes detailed instructions on how to suppress it and how to prepare for the change.
Let me know what you all think about it.
Relates to #4176 #2334