Syntax Proposal - "And-then-style" function-chain call

Proper argument is “This symbol is looking good as itself, and in some languages it is already means the same, and, by the way, it already has nice ligatures in some IDEs”. Last one is not a proper argument, if we get it as isolate suggestion, but it is seems a bonus, if first two arguments are true.

5 Likes

‘\’ might be hard to understand for someone who has never seen it before. Out of context, it makes no sense. Perhaps we could use something like ‘=>’, or, if that causes confusion in maps and such, we could use ‘->’ or ‘–>’.

=> is not a valid identifier, I think. -> confuses with tuples, but I’d say either |> or --> look fine.

1 Like

Another nice consequence of this construction: function declaration by chain.

def f(x1: Int, x2: Int) = (s"f($x1)", s"f($x2)")

def g(x1: String, x2: String) = s"g($x1, $x2)"

val myF = (_: (Int, Int))
  |> f
  |> g

val result = (1, 2) |> myF 
(*  g(f(1), f(2))  *)

I’d say that would use a different function, like ||>, since |> tries to pass the tuple directly

I like how those look as well. Seems I forgot this was for a standard library proposal and not a SIP. I would be wary with ‘|>’, as it may confuse people coming from OCaml.

If you think of match as (partial-)function application, you could in theory have Scala do:

x match fun1 match fun2 match fun3 and have that interpreted as fun3(fun2(fun1(x)))

2 Likes

It is fine to have “||>” as pseudonym for “andThen”, but my example works “from the box”.

If we add definition from main topic…

extension [T](x: T) inline def |>[R](f: T => R) = f(x)

…then the code, I wrote for this example, already works. No need to add something else. You can just replace first part of

(1, 2) |> f |> g

to

(_: (Int, Int)) |> f |> g

and you already have function definition — with the same earlier defined inline-extension. It is the way how Scala 3 compiler works now.

1 Like

Oh whoops, I never noticed that. So

def f(x: Int, y: String) = s"$x and $y"

val tup = (3, "hi")

f(tup)

works? Nice, also what about

def f(tup: (Int, String)) = s"tupled $tup"
def f(i: Int, s: String) = s"expanded $i $s"
f(tup)

It gives “f is already defined” error. Just because, as I see, now it means the same.

oh that’s weird

I like how that looks and that it is reusing an existing keyword.

1 Like

I think, it is rather logical and convenient. For example, now we don’t have to write…

val list = List((1, 2), (3, 4))
list.map{case (x, y) => x + y}

…but can write instead

list.map(_ + _)

And now it is much easier to build a chain from functions, these get multiple arguments and return multiple results.

No no, that generally they are interchangable is nice, what isn’t is that they’re considered the same exact function so you can’t differenciate between a tuple and a series of arguments

I’ve tried. If I make them methods, they can exists at the same time without error. And can be called as

f(1, "2")

or

f((1, "2"))

accordingly.

Code of

(1, "2") |> f

calls the tuple-one, if they both are defined, but, if two-arguments-one exists only, it calls this one.

So, if they are methods, they are different.

Exactly, that’s why you need a extension [A, B] (t: (a, B) inline def ||>[R](f: (A, B) => R) = f(t._1, t._2) etc, to specifically “spread” the Tuple and choose the teo-arg function

It seems right: for overloaded method it needs series of definitions too distinguish, which one we want too call. Or some type-lambdas magic, which I don’t know how to write, this day.

Scala already has infix-style calls, since long time ago. It is not a new thing. And, of course, IDEs support it.