Pipeline operator?

Some languages like F#, Rescript, have a pipeline forward operator, there is also an Emacscript proposal, is there any change something like that goes standard library? works nicely with curried functions

/** Pipeline operator */
extension [A, B](a: A) 
    infix def |>(f: A => B): B = f(a)

val triple = (x: Int) => 3 * x
val half = (x: Int) => x / 2
val sum = (x: Int) =>  (y: Int) => x + y

/** Instead of */
val classic = half(sum(triple(3))(2))

/** Pipe the functions */
val piped = 3
    |> triple 
    |> sum(2) // curried
    |> half

The worksheet output



There is a pipe method in the standard library available as an extension method.

You need

import scala.util.chaining.scalaUtilChainingOps

or just

import scala.util.chaining._

Thanks for bringing that out, indeed it does the job.


Used it one liner because for some reason using multiple lines throws errors on pipe, unless you use posfix notation

Still think the pipe operator is cleaner

Relevant to this discussion:

“Style Guide / Naming Conventions” describes when to use operators rather than names.

I like the Style Guide, as overusing symbolic names makes code IMO harder to understand if you don’t use the operators daily or are a beginner - a good name says more than a good symbol(s).

If the Style Guide applies to this case is an open question for me, just wanted to link the Style Guide here.

1 Like

I also would prefer an operator such as |> for pipe. I think the operator is by now common enough to be easily recognizable. And the advantage is its an operator, so it can be written at the start of a new line without needing a . in front.


Hi all,

In case it interests anyone, I have some slides (10 to 16) on the pipe operator in this deck (download for best results):

The first of the slides in question:


This was fantastic, Philip!

Tysvm for posting the image. It was because of the image I decided to visit the links.


This summer someone proposed adding the operator in Haskell. The discussion was very involved: Add the ‘|>’ pipe operator


Altogether we have 2 votes in favor, 3 votes against, and chessai is on a temporary leave (#82). Even if he votes in favor, we still fall short of 4 votes required to approve the proposal. Thanks all for the discussion (and foremost to @chshersh), unfortunately, the proposal is declined.

1 Like

@chaotic3quilibrium You are too kind :pray: - I am so glad you found it useful - Thanks.

1 Like

In case this is added, then I hope that the operator |> will still be free for our own DSL’s. For example by making |> available as import extension just like pipe, and not a generic operator on all types by default. That would for example interfere with my DSL, which has operators like |>, |+ etc.

BTW, i have also defined a pipe operator for every day use long ago (probably like many others). The: | (modelled after the bash pipe operator). Imho this is just as readable, and simpler:

val res = 3 | triple | sum(2) | half
1 Like

The | operator is already used to define unions.

Used on types, the | operator creates a so-called union type . The type A | B represents values that are either of the type A or of the type B .

1 Like

In Elixir it’s |> too https://elixir-lang.org

1 Like

Here is a previous discussion: Give The pipe Method of scala.util.ChainingOps An Operator Representation - Language Design - Scala Contributors (scala-lang.org), and I think the first response of it is very useful.

1 Like

The last response is most useful, indeed. That’s a clever idea, for shift-enter in REPL to go into pipeline mode.

I’m not a fan of declaring “you can’t use this feature because it hurts performance unless you use knobs or maybe it doesn’t matter.” There are plenty of cases where JVM performance was affected for various reasons one would prefer not to care about.

import scala.util.chaining._

final class C {
  def s = "hello, world"
  def f = s pipe len
  def len(x: String) = x.length

In Scala 2, -opt:inline results in

  public int f();
    descriptor: ()I
    flags: (0x0001) ACC_PUBLIC
      stack=1, locals=1, args_size=1
         0: getstatic     #27                 // Field scala/util/ChainingOps$.MODULE$:Lscala/util/ChainingOps$;
         3: pop
         4: getstatic     #30                 // Field scala/util/package$chaining$.MODULE$:Lscala/util/package$chaining$;
         7: pop
         8: ldc           #17                 // String hello, world
        10: invokevirtual #35                 // Method java/lang/String.length:()I
        13: ireturn

I think there is also a lever for mitigating module loads?

I’m a big fan of expr.tap(init(_)) where it’s obvious up front what I’m getting and that some side effects happen by the way. Often it also saves braces.

True, although those applications would not interfere i guess. But besides that, i defined the operator long before it was defined as type union and use it all over the place. This can be an issue with other new operators and keywords that are defined later on as well. That people already have them in use for something else. (enum anyone? :wink:)

Anyway, i don’t say the | operator is better or so, the only thing i would like is that new operators are not ‘imported by default’, thereby interfering with DSL’s.

it also defined as |> for Flix and and Elm

some of them like F#, Elm also have the pipe backward <|

In Scala 3, inline in the source takes care of (at least most of) it. I have yet to find a case where the following is slower than writing things out by hand in microbenchmarks.

extension [A](a: A) {
  inline def pipe[B](inline f: A => B): B = f(a)
1 Like

we can also transform

val piped = 3
    |> triple 
    |> sum(2) // curried
    |> half


val classic = half(sum(triple(3))(2))

at compile time, similar of how the s"Hello, $name" string interpolator is rewritten by compiler

That basically is what happens with inline in Scala 3, except it’s not a special case like the string interpolator.