Since the Semigroup-Monoid Proposal has landed, the data type Option from Data.Semigroup is now obsolete. I propose that it be marked deprecated in GHC 8.6 and removed in GHC 8.10.
I figured it would be best to track all of these on the same ticket. In a response to the aforementioned mailing list thread, Edward Kmett suggested that the timing for deprecation and removal be GHC 8.8 and GHC 8.10 respectively. This will make it possible to adhere to the three-release policy with ease.
Andrew Martinchanged title from Deprecate and Remove Data.Semigroup.Option/First/Last to Deprecate and Remove Data.Semigroup.Option and Data.Monoid.First/Last
changed title from Deprecate and Remove Data.Semigroup.Option/First/Last to Deprecate and Remove Data.Semigroup.Option and Data.Monoid.First/Last
Now that I'm working on implementing the deprecations in !842 (closed), I suspect that deprecating Option in GHC-8.8 would actually violate the 3-release-policy.
The problem is that the instance Semigroup a => Monoid (Maybe a) was only added in GHC-8.4. In my reading of the 3-release-policy that means that we have to wait until GHC-8.10 to deprecate Option since only then will Maybe's new instance have existed for three GHC releases (8.4, 8.6 and 8.8).
My reasoning is based on the "without causing warnings" bit from the policy:
Changes to basic libraries are planned and implemented so that, at any time, it is possible to write code that works with the latest three releases of GHC and base, without resorting to CPP, and without causing warnings even when compiled with -Wall.
I'm still hesitating to actually merge my patch (!842 (closed)).
I suspect that only once people start migrating from Data.Monoid.{First,Last} to Data.Semigroup.{First,Last} they will find out that the ecosystem support isn't quite there yet. Mostly I'm expecting missing instances, some of which I've already discovered (#16636).
As some sort of smoke testing, I've made a patch for the summoner package which heavily relied on Data.Monoid.Last for their "Higher Kinded Data"-style configuration. Surprisingly to me this went rather well, revealing only a small problem with generic-deriving. The increased noise from fmapping Last and getLast is regrettable but expected.
I would be interested to hear some opinions on these concerns. Ultimately I'm wondering though whether the deprecation should be delayed or whether it's tradeoffs should be entirely reevaluated.
Firstly, thanks for doing a smoke test and identifying difficulties that would result from implementing the implementing the proposal. That’s extremely useful.
The missing instances for Eq1, Show1, etc. are likely a problem for users who want to use First or Last with data types that use the higher-kinded-records design pattern. In addition to these instances, it would be prudent to ensure that instances for the higher kinded variants of the type classes in aeson and hashable are present as well. I think we should add the missing instances to base and then wait another three releases before deprecating. I don’t see a compelling reason to reevaluate the proposal in its entirety. It originally received broad support on the mailing list, and there have not been any changes in the ecosystem that nullify any of the motivations behind it. The oversight of the type class instances is regrettable, but I think the elimination of these redundant types is still a worthwhile long-term goal.
There's certainly no issue with holding back the release in which we deprecate these types (the Haddocks currently promise 8.8 as that release, but we can always change that). If the only issue you've discovered is #16636, however, then the situation isn't too dire, since we can always backport new instances via the base-orphans/semigroups packages.
@sjakobi I appreciate your effort on testing this change on a project like summoner, however, as one of the summoner maintainers I see much more troubles in this change:
Noise from fmaping and wrapping can be annoying. I kinda like how newtype Last a = Last { getLast :: Maybe a } provides smart Functor instance, so I don't need to do nested fmaps.
Last also has nice Applicative instance that allows me to wrap values inside it by simply calling pure x (or with type applications if I prefer more explicit approach: pure @Last x).
summoner depends on the relude alternative prelude and currently relude reexports Last from Data.Monoid:
https://hackage.haskell.org/package/relude-0.5.0/docs/src/Relude.Monoid.html
First, deprecating and removing Last/First from Data.Monoid will not only require some dancing in summoner but also introducing breaking changes to relude with possible -XCPP maintenance burden. Second, it's a highly major breaking change which will make the life of relude users more complicated. If Last is removed from Data.Monoid then I would rather introduce it in relude by copy-pasting current code from base instead of reexporting from Data.Semigroup.
My main concern here is that I find Last and First data types from Data.Monoid pretty useful and I don't see much benefits in removing them. I never had to use Maybe (Last a), and I find current Last much more useful and convenient, so if I have to choose between two data types, I will always prefer monoidal Last because it's merely convenient, and removing this data type just makes life harder and less convenient with no significant benefit.
I can see value in resolving ambiguity between Data.Semigroup.Last and Data.Monoid.Last, however, it seems like instead of assigning different meaning to the already existing word Last by introducing one more data type with the same name to the core library, data type with different name could be introduced instead, like Latter or End or TakeLast or KeepLast or LastSemigroup or Back or Ending or Terminal or something else.
Basically, current base provides two options for the monoid with the Last behaviour, but instead of removing one of the types, why not just write better documentation telling which data type to use in what use cases, what are the pros and cons of every data type, what difference in usage you can expect, etc? For me, it seems like everybody will benefit from this action and nobody will be hurt.
I see that the Haddock for Last and First tells that this data type will be deprecated and removed, but I learned about this fact only because somebody spent his free time to contribute to my library and linked to this issue from the pull request. I don't spend my free time rereading Haddocks for every data type and function in base, so if not this PR, I could learn about this change only post-factum after all decisions are made, which makes the process of contributing to the Haskell ecosystem frustrating. I think, as a very small and fragmented community we should focus on distributing knowledge about breaking changes in advance and collect opinions from the community first instead of notifying all Haskell users about made breaking changes.
P.S. I'm neutral about deprecating and removing Option data type, I don't use it. Option already contains alternative (which is Maybe and which is more convenient than this newtype).
I've somewhat lost my motivation to work on this issue. I believe that before we can deprecate D.M.First and D.M.Last we should make sure that D.S.{First,Last} can fill the gap in an acceptable way. In the HKD-space, converting higgledy could be an another interesting test case. lens also uses D.M.First quite a bit.
Depending on how costly the migration away from D.M.{First,Last} turns out, I think renaming D.S.{First,Last} could be the better way of resolving the ambiguity. My impression so far is that these types get very little use in the wild.
The Option deprecation should still go forward. I can simply extract those bits from !842 (closed). @bgamari: Is there still time to do this in v8.8 or should it wait for 8.10?
My impression so far is that these types get very little use in the wild.
I think renaming D.S.{First,Last} could be the better way of resolving the ambiguity. My impression so far is that these types get very little use in the wild.
This sounds reasonable to me; do you want to bring this idea to the libraries list? Even if you want to set this issue aside, it would be great if we could at least get this option on the record.
Sorry for dropping the ball on this ticket. Unfortunately this has caused some confusion as some users assumed that the deprecation would proceed as planned. See e.g. https://github.com/conal/checkers/issues/44.
In the meantime, more evidence that Data.Monoid.First isn't as easy to replace as initially believed has come up: #17967 (closed)
@chessai, @carter, as the new base maintainers, what do you think about this?
I'm not really in favour of the deprecation. #17967 (closed) is more evidence of this, since it's not really plausible to replicate the same strictness semantics with Option+Data.Semigroup.First. I often in my own code do something like:
import qualified Data.Monoid as Monoid...reference to Monoid.First...
and/or
import qualified Data.Semigroup as Semigroup...reference to Semigroup.First...
To me, the distinction in behaviour is clear because of my understanding of Semigroup/Monoid. And I don't need to worry about Option.
I realise I might be in the minourity here and I'm willing to be convinced otherwise. @sjakobi have you brought up @bgamari's suggestion to the libraries mailing list? That might be a good first step, given the new information about the migration story.