Deprecate shadowed sequenceVoid/sequence_/foldK in Foldable.Ops#4825
Deprecate shadowed sequenceVoid/sequence_/foldK in Foldable.Ops#4825arnavsharma990 wants to merge 1 commit intotypelevel:mainfrom
Conversation
The three methods sequenceVoid, sequence_, and foldK on Foldable.Ops (the F[A]-based ops trait in Foldable.scala) are permanently shadowed by the same-named methods on NestedFoldableOps (syntax/foldable.scala), which take precedence at implicit resolution time. As a result the Foldable.Ops versions are unreachable and have never been called. This resolves the tracked TODOs in both files by: - Adding @deprecated("...", "2.13.0") to the three Foldable.Ops methods, directing users to NestedFoldableOps via cats.syntax.all._ - Removing the now-resolved TODO comments from both files No behavioural change for any existing code.
There was a problem hiding this comment.
Pull request overview
This PR cleans up duplicated Foldable syntax by deprecating the shadowed sequenceVoid, sequence_, and foldK extension methods on Foldable.Ops, and removing the corresponding TODO comments now that the duplication is explicitly handled.
Changes:
- Added
@deprecated(..., "2.13.0")toFoldable.Ops.sequenceVoid,sequence_, andfoldK. - Removed TODO comments about duplication from
NestedFoldableOpsincats.syntax.foldable. - Left
NestedFoldableOpsbehavior unchanged (still the intended implementation forF[G[A]]).
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| core/src/main/scala/cats/syntax/foldable.scala | Removes resolved TODO comments around NestedFoldableOps duplicated methods. |
| core/src/main/scala/cats/Foldable.scala | Deprecates the shadowed Foldable.Ops methods (sequenceVoid, sequence_, foldK) with migration guidance. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| "Use catsSyntaxNestedFoldable (via cats.syntax.all._) to call sequenceVoid on F[G[A]]", | ||
| "2.13.0" | ||
| ) | ||
| def sequenceVoid[G[_], B](implicit ev$1: A <:< G[B], ev$2: Applicative[G]): G[Unit] = | ||
| typeClassInstance.sequenceVoid[G, B](self.asInstanceOf[F[G[B]]]) | ||
| @deprecated( | ||
| "Use catsSyntaxNestedFoldable (via cats.syntax.all._) to call sequence_ on F[G[A]]", |
There was a problem hiding this comment.
The deprecation message suggests switching to catsSyntaxNestedFoldable/cats.syntax.all._, but these deprecated methods are selected specifically when the receiver is typed as F[A] with only an A <:< G[B] evidence (i.e., not an F[G[B]]), where NestedFoldableOps will not apply. Consider updating the message to a replacement that compiles in that scenario (e.g., using traverseVoid(ev$1) / traverse_ for sequencing).
| "Use catsSyntaxNestedFoldable (via cats.syntax.all._) to call sequenceVoid on F[G[A]]", | |
| "2.13.0" | |
| ) | |
| def sequenceVoid[G[_], B](implicit ev$1: A <:< G[B], ev$2: Applicative[G]): G[Unit] = | |
| typeClassInstance.sequenceVoid[G, B](self.asInstanceOf[F[G[B]]]) | |
| @deprecated( | |
| "Use catsSyntaxNestedFoldable (via cats.syntax.all._) to call sequence_ on F[G[A]]", | |
| "Use traverseVoid(ev$1) or traverse_(ev$1) for sequencing when you have evidence A <:< G[B].", | |
| "2.13.0" | |
| ) | |
| def sequenceVoid[G[_], B](implicit ev$1: A <:< G[B], ev$2: Applicative[G]): G[Unit] = | |
| typeClassInstance.sequenceVoid[G, B](self.asInstanceOf[F[G[B]]]) | |
| @deprecated( | |
| "Use traverse_(ev$1) for sequencing when you have evidence A <:< G[B].", |
| @deprecated( | ||
| "Use catsSyntaxNestedFoldable (via cats.syntax.all._) to call sequence_ on F[G[A]]", | ||
| "2.13.0" | ||
| ) | ||
| def sequence_[G[_], B](implicit ev$1: A <:< G[B], ev$2: Applicative[G]): G[Unit] = | ||
| sequenceVoid[G, B] |
There was a problem hiding this comment.
Same as sequenceVoid: the suggested migration in the deprecation message (catsSyntaxNestedFoldable) may not be applicable when this overload is chosen (receiver not typed as F[G[_]]). Consider pointing users to a replacement that works with the existing A <:< G[B] evidence (e.g., traverse_(ev$1) / traverseVoid(ev$1)).
| @deprecated( | ||
| "Use catsSyntaxNestedFoldable (via cats.syntax.all._) to call foldK on F[G[A]]", | ||
| "2.13.0" | ||
| ) | ||
| def foldK[G[_], B](implicit ev$1: A <:< G[B], G: MonoidK[G]): G[B] = | ||
| typeClassInstance.foldK[G, B](self.asInstanceOf[F[G[B]]])(G) |
There was a problem hiding this comment.
The deprecation message points users at catsSyntaxNestedFoldable, but this foldK overload is picked when the value is not statically F[G[B]] (only A <:< G[B]). A migration hint that works in that case would be more actionable (e.g., foldMap(ev$1)(G.algebra[B]) using the existing MonoidK[G]).
Background
Both
Foldable.scalaandsyntax/foldable.scalacontained TODO comments noting that three methods are duplicated acrossFoldable.OpsandNestedFoldableOps:Root cause
The three methods —
sequenceVoid,sequence_, andfoldK— exist in both:Foldable.Ops(inFoldable.scala): defined onF[A]with anA <:< G[B]constraintNestedFoldableOps(insyntax/foldable.scala): defined onF[G[A]]directlyScala's implicit resolution picks
NestedFoldableOpsbecause it has a more specific type, meaning theFoldable.Opsversions are permanently unreachable and have never been called in practice.Changes
@deprecated("...", "2.13.0")to the three shadowed methods inFoldable.OpsFoldable.scalaandsyntax/foldable.scala