From a27968416eb7aef8f760e8ac8e57e6cb4fb13c34 Mon Sep 17 00:00:00 2001 From: Arnav Sharma <2006arnavsharma@gmail.com> Date: Fri, 20 Feb 2026 09:00:16 +0000 Subject: [PATCH] Deprecate shadowed sequenceVoid/sequence_/foldK in Foldable.Ops 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. --- core/src/main/scala/cats/Foldable.scala | 15 ++++++++++++--- core/src/main/scala/cats/syntax/foldable.scala | 4 ---- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/core/src/main/scala/cats/Foldable.scala b/core/src/main/scala/cats/Foldable.scala index 70db2e7cd3..b0fb336e8b 100644 --- a/core/src/main/scala/cats/Foldable.scala +++ b/core/src/main/scala/cats/Foldable.scala @@ -1073,13 +1073,22 @@ object Foldable { typeClassInstance.traverseVoid[G, A, B](self)(f)(G) def traverse_[G[_], B](f: A => G[B])(implicit G: Applicative[G]): G[Unit] = traverseVoid[G, B](f) - // TODO: looks like these two methods below duplicate the same named methods from `NestedFoldableOps`. - // Moreover, the other two methods take precedence, thereby these two are not in use whatsoever. - // Perhaps it makes sense to deprecate one pair of them either here or there. + @deprecated( + "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]]", + "2.13.0" + ) def sequence_[G[_], B](implicit ev$1: A <:< G[B], ev$2: Applicative[G]): G[Unit] = sequenceVoid[G, B] + @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) def find(f: A => Boolean): Option[A] = typeClassInstance.find[A](self)(f) diff --git a/core/src/main/scala/cats/syntax/foldable.scala b/core/src/main/scala/cats/syntax/foldable.scala index b70eb71674..a916fba90b 100644 --- a/core/src/main/scala/cats/syntax/foldable.scala +++ b/core/src/main/scala/cats/syntax/foldable.scala @@ -47,8 +47,6 @@ private[syntax] trait FoldableSyntaxBinCompat1 { } final class NestedFoldableOps[F[_], G[_], A](private val fga: F[G[A]]) extends AnyVal { - // TODO: looks like these two methods below duplicate the same named methods from `Foldable.Ops`. - // Perhaps it makes sense to deprecate one pair of them either here or there. def sequenceVoid(implicit F: Foldable[F], G: Applicative[G]): G[Unit] = F.sequenceVoid(fga) def sequence_(implicit F: Foldable[F], G: Applicative[G]): G[Unit] = sequenceVoid @@ -64,8 +62,6 @@ final class NestedFoldableOps[F[_], G[_], A](private val fga: F[G[A]]) extends A * res0: Set[Int] = Set(1, 2, 3, 4) * }}} */ - // TODO: looks like this method below duplicate the same named one from `Foldable.Ops`. - // Perhaps it makes sense to deprecate one of them. def foldK(implicit F: Foldable[F], G: MonoidK[G]): G[A] = F.foldK(fga) }