Pipeline operator?

is better than

because it doesn’t require parentheses around Math.sqrt

a.zip(b).map(_ * _).sum.|>(Math.sqrt)

Scala 2 is agnostic about the invocation style (infix vs dotted selection).

Scala 3 wants only symbolic operators for infix, though you can backtick an alnum:

def f = s `pipe` len  // from my previous comment

def check(x: AnyRef, y: AnyRef) = x.eq(y)  // we used to write (x eq y)

It turns out that the old style of omitting dots and parentheses failed to avert global warming and shrink the Great Pacific Garbage Patch.

Since I tend to need them for ease of reading, I use as many as necessary, guilt-free.

But symbolic operators can be tastefully applied. The discussion was about how to indicate that “pipe” is a synonym, in order to make it easier to search documentation. I don’t remember if they invented a mechanism for that. Maybe the alpha annotation.

1 Like

Maybe it would be great to return /: and :/ back to Scala? These operators was really great :slight_smile:

1 Like

I see! I didn’t know about the infix notation. Now that I do, here’s another attempt at the distance function:

(a zip b).map(_ * _).sum pipe Math.sqrt

In this version, I love the infix zip, but I’m a little iffy about the infix pipe because I don’t really think of pipe as an infix operator. In my mind, every time I see pipe used over and over with the same function, that’s an indicator that this function should really be made available as a method. For example:

(a zip b).map(_ * _).sum.sqrt

Or even

(a zip b).map(_ * _).sum.(Math.sqrt)

As you can see, . and .pipe mean the same thing in this situation. Would it be possible to overload . to behave like .pipe in situations like this? Or would that overload . too much?

That seems like it would be really easy to mix up with the sugar for .apply

3 Likes

By coincidence, I read the PR thread on “implicit application syntax” for Dotty from 2017-18 or so, and someone did propose dot application. I wish I could find it amongst those long, long threads. I just wanted to point out that it came up at least once, in a certain context.

Edit: dot application

implicit val str: String = "x = "
def foo(x: Int).(y: String) = y+x
foo(0) // "x = 0"
foo(1).("Value: ") // "Value: 1"
1 Like

Thank you to everyone who responded so far. I feel like I need to come back to this discussion after learning more Scala!

If you’re interested, here’s the “opposite” discussion on the F# github about adding the fluent . methods to FSharp Core. Consider incorporating FSharp.Core.Fluent into FSharp.Core · Issue #1073 · fsharp/fslang-suggestions · GitHub. The majority of votes are against the proposal.

I love piping partial functions all day long, and I think I’ll find out soon enough how often I need to use .pipe to do so. But adding an operator, even a common one like |>, is a slippery slope. If Scala adds |>, it will probably open the floodgates for people asking for more symbolic operators for compose, andThen, etc. And it will certainly open the floodgates for people writing functions where the main argument comes last, not first. All of which detract from the Subject Verb Object essence of Scala? (Fresh eyes here–not sure if this is actually the essence of Scala :slight_smile: )

I think .pipe adds a little bit of friction and reminds library authors that super common functions should be exposed as methods for easier chaining.

1 Like

This happened already in the past. Scala was for some time considered the Perl of JVM languages, written in the most obscure symbolic operators. :grin:

Thanks god most of the proponents are back to Haskell (or whatever other language without IDE friendly syntax).

Even the Haskell clone libs in Scala don’t write code backwards anymore but use method syntax.

1 Like

Yikes, I just realized that I got the distance formula wrong! The correct formula is:

(a zip b).map(_ - _).map(x => x * x).sum.pipe(Math.sqrt)
1 Like

Roc-lang use |> too

If Scala adds |> , it will probably open the floodgates for people asking for more symbolic operators for compose , andThen , etc.

An excerpt from Sergei Winitzki’s book: https://github.com/winitzki/sofp:

1 Like

Here you see the difficulty with choosing method names. f andThen g is completely self explanatory, f will be applied first and then comes g. But f compose g ?? This can be either way. After many years of Scala programming i still have to look it up to be sure. f butFirst g would have been a lot clearer for example, and it is also obvious that andThen and butFirst are antagonists. BTW, before and after would have been perfect as well. Equally clear and simpler.

Let me not start on those operators, great for personal libraries, but not for the standard.

1 Like

Agreed that compose is not a very intuitive name, and I don’t think I ever use that operator. But there is some logic behind the name. It is borrowed from mathematical function composition.

Quoting wikipedia:

In mathematics, function composition is an operation ∘ that takes two functions f and g, and produces a function h = gf such that h(x) = g(f(x)).

I might have gone with f after g.

1 Like

I do like map and contramap, which you can kind of get to with Cats, though the type inferencing doesn’t quite seem to be able to make the connection (which shouldn’t be an issue if implemented as a member, rather than through a typeclass).

  import cats.syntax.all._
  import cats.Contravariant

  val f: Float => Int = ???
  val g: Int => String = ???
  
  val fg: Float => String = f.map(g)
  val gf: Float => String = Contravariant[* => String].contramap(g)(f)
  // Sadly, this doesn't work:
  g.contramap(f)
  // It's equivalent to this, which does work:
  toContravariantOps[* => String, Int](g)(cats.Invariant.catsContravariantForFunction1).contramap(f)
1 Like

Even Bartosz Milewski says the following:

In math, such composition is denoted by a small circle between functions: g∘f. Notice the right to left order of composition. For some people this is confusing.

2 Likes

Just for interest, there is a combinator called the blackbird, which is the combination of combination and combination!

1 Like