Exhibit A:
scala> import scala.util.chaining.*
scala> 1.pipe(_ : Vector(2,3))
val res1: Vector[Int] = Vector(1, 2, 3)
// if you don't have a sweet tooth:
scala> 1.pipe(i => i : Vector(2,3))
val res2: Vector[Int] = Vector(1, 2, 3)
However, the pipe operator makes sense in languages that define functions, not methods. That's not how it is in true object-oriented languages like Scala where dot notation and extension methods are vastly better.
Exhibit B:
Assuming we have a generic `def movingAverage(coll: COLL[Int], windowSize: Int): COLL[Double]`
scala> (1 to 8).toVector.pipe(movingAverage(_, 4))
val res3: Vector[Double] = Vector(2.5, 3.5, 4.5, 5.5, 6.5)
scastie.scala-lang.org/LI4ZD…
and with an extension method:
scala> (1 to 8).toVector.movingAverage(4)
val res4: Vector[Double] = Vector(2.5, 3.5, 4.5, 5.5, 6.5)
scastie.scala-lang.org/mAZrr…
Addendum - let's have some fun with hieroglyphics:
scala> extension [A](a: A) def |>[B](f: A => B): B = f(a)
def |>[A](a: A)[B](f: A => B): B
because why not, we're already using one of the most expressive languages in the world, we can just define the pipe operator.
This won't compile unfortunately:
scala> (1 to 8).toVector |> movingAverage(_, 4)
forcing us to do something less than pretty:
scala> (1 to 8).toVector |> (v => movingAverage(v, 4))
val res5: Vector[Double] = Vector(2.5, 3.5, 4.5, 5.5, 6.5)
Extension methods and dot notation wins with pipes almost every single time:
scala> (1 to 8).toVector.movingAverage(4)
But you could have just curried the function, this is sad, Haskell auto-curries all functions, Scala bad!
Scala is not Haskell and the type system is different. Attempts to convert a generic contextual function to a curried variant defined as a polymorphic function type will leave you in tears.