From 190a1588160d5b3073fc340882f96d21ad8c425c Mon Sep 17 00:00:00 2001 From: Hamza Remmal Date: Thu, 11 Dec 2025 00:35:19 +0100 Subject: [PATCH 1/2] chore: deprecate `scala.util.ChainingOps` --- compiler/test/dotty/tools/utils.scala | 2 +- library/src/scala/util/ChainingOps.scala | 13 +++++++------ library/src/scala/util/package.scala | 10 ++++++++-- repl/test/dotty/tools/repl/StackTraceTest.scala | 2 +- tests/neg/i15998.check | 1 - tests/run/i10889.scala | 2 +- tests/run/i11571.scala | 2 +- 7 files changed, 19 insertions(+), 13 deletions(-) diff --git a/compiler/test/dotty/tools/utils.scala b/compiler/test/dotty/tools/utils.scala index 37ef2542be4b..0c051f8c8bbc 100644 --- a/compiler/test/dotty/tools/utils.scala +++ b/compiler/test/dotty/tools/utils.scala @@ -12,7 +12,7 @@ import scala.io.Source import scala.jdk.StreamConverters._ import scala.reflect.ClassTag import scala.util.Using.{Releasable, resource} -import scala.util.chaining.given +import scala.util.chaining.* import scala.util.control.{ControlThrowable, NonFatal} import dotc.config.CommandLineParser diff --git a/library/src/scala/util/ChainingOps.scala b/library/src/scala/util/ChainingOps.scala index 41526bffbb46..1a405f67ab49 100644 --- a/library/src/scala/util/ChainingOps.scala +++ b/library/src/scala/util/ChainingOps.scala @@ -16,12 +16,16 @@ package util import scala.language.`2.13` import scala.language.implicitConversions +@deprecated(message = "ChainingSyntax will be removed in the future. Refer to `scala.util.chaining` instead.", + since = "3.10.0") trait ChainingSyntax { - @inline implicit final def scalaUtilChainingOps[A](a: A): ChainingOps[A] = new ChainingOps(a) + @deprecated(message = "Use extension methods in `scala.util.chaining` instead.", since = "3.10.0") + @inline final def scalaUtilChainingOps[A](a: A): ChainingOps[A] = new ChainingOps(a) } /** Adds chaining methods `tap` and `pipe` to every type. */ +@deprecated(message = "Use extension methods in `scala.util.chaining` instead.", since = "3.10.0") final class ChainingOps[A](private val self: A) extends AnyVal { /** Applies `f` to the value for its side effects, and returns the original value. * @@ -37,10 +41,7 @@ final class ChainingOps[A](private val self: A) extends AnyVal { * @tparam U the result type of the function `f`. * @return the original value `self`. */ - def tap[U](f: A => U): A = { - f(self) - self - } + def tap[U](f: A => U): A = scala.util.chaining.tap(self)(x => f(x)) /** Converts the value by applying the function `f`. * @@ -62,5 +63,5 @@ final class ChainingOps[A](private val self: A) extends AnyVal { * @return a new value resulting from applying the given function * `f` to this value. */ - def pipe[B](f: A => B): B = f(self) + def pipe[B](f: A => B): B = scala.util.chaining.pipe(self)(f) } diff --git a/library/src/scala/util/package.scala b/library/src/scala/util/package.scala index 7d1fe27bdde8..69f5e434687f 100644 --- a/library/src/scala/util/package.scala +++ b/library/src/scala/util/package.scala @@ -14,9 +14,15 @@ package scala import scala.language.`2.13` +import scala.annotation.nowarn + package object util { /** - * Adds chaining methods `tap` and `pipe` to every type. See [[ChainingOps]]. + * Adds chaining methods `tap` and `pipe` to every type. */ - object chaining extends ChainingSyntax + @nowarn("msg=ChainingSyntax will be removed in the future") + object chaining extends ChainingSyntax: + extension[A](x: A) + inline def tap(inline f: A => Unit): x.type = { f(x); x } + inline def pipe[B](inline f: A => B): B = f(x) } diff --git a/repl/test/dotty/tools/repl/StackTraceTest.scala b/repl/test/dotty/tools/repl/StackTraceTest.scala index 03863ffce1cc..cc7d474db445 100644 --- a/repl/test/dotty/tools/repl/StackTraceTest.scala +++ b/repl/test/dotty/tools/repl/StackTraceTest.scala @@ -4,7 +4,7 @@ package dotty.tools.repl import scala.language.unsafeNulls import scala.util.{Failure, Success, Try} -import scala.util.chaining.given +import scala.util.chaining.* import org.junit.Assert.{assertEquals, assertTrue} import org.junit.Test diff --git a/tests/neg/i15998.check b/tests/neg/i15998.check index 587a8ca100f0..66bd4c0cdc29 100644 --- a/tests/neg/i15998.check +++ b/tests/neg/i15998.check @@ -15,7 +15,6 @@ | import scala.math.BigDecimal.int2bigDecimal | import scala.math.BigInt.int2bigInt | import scala.math.Ordered.orderingToOrdered - | import scala.util.chaining.scalaUtilChainingOps | | | longer explanation available when compiling with `-explain` diff --git a/tests/run/i10889.scala b/tests/run/i10889.scala index 130b6d2d9636..8857d146acf9 100644 --- a/tests/run/i10889.scala +++ b/tests/run/i10889.scala @@ -1,5 +1,5 @@ import scala.annotation.tailrec -import scala.util.chaining.given +import scala.util.chaining.* object Test { class Ctx diff --git a/tests/run/i11571.scala b/tests/run/i11571.scala index 5bd6af3336e0..0fa019ebc204 100644 --- a/tests/run/i11571.scala +++ b/tests/run/i11571.scala @@ -1,4 +1,4 @@ -import util.chaining.scalaUtilChainingOps +import util.chaining.* object Test extends App { def x = 42.tap(println(_)) def y = 27.tap(println(_)) From 6aee5bd7c16e97195c9d62f5a0e2a4d1fce917ae Mon Sep 17 00:00:00 2001 From: Hamza Remmal Date: Thu, 11 Dec 2025 02:00:01 +0100 Subject: [PATCH 2/2] chore: add the `|>` operator for `pipe` --- library/src/scala/util/package.scala | 1 + 1 file changed, 1 insertion(+) diff --git a/library/src/scala/util/package.scala b/library/src/scala/util/package.scala index 69f5e434687f..32bfa07ca087 100644 --- a/library/src/scala/util/package.scala +++ b/library/src/scala/util/package.scala @@ -25,4 +25,5 @@ package object util { extension[A](x: A) inline def tap(inline f: A => Unit): x.type = { f(x); x } inline def pipe[B](inline f: A => B): B = f(x) + inline infix def |> [B](inline f: A => B): B = x.pipe(f) }