I really appreciate decreasing braces quantity in Scala, this way, I want to suggest some extension to Scala standard library.
When we have a list, it is easy to define function chain, in a way we speaking on human languages.
val res = list
.map(_ + 1)
.filter(_ > 0)
It is read literally: “get a list, and then add 1 to every element, and then take elements, which are more than 0”.
We can do the same with function construction too.
val f =
f1 andThen
f2 andThen
f3
But when we call a function chain, we cannot write it in “and-then” style. We have to write it like
val res = f3(f2(f1(x)))
The problems are:
- Too many braces in a long call-chain.
- It is hard to read (even if we split it on several lines).
- If we’ll split it on several lines, we’ll get many visual nesting levels.
- Moreover, it is in reversed order, comparing with order of our speaking and thinking.
We don’t say: “Do f3 with thing, that we’ll get after calling f2 with thing, that we get after…”. We say, instead: “Get x, and then do f1 with that, and then do f2 with result, and then…”.
Wolfram language has nice construction, like “andThen”, but for function chain calling instead of function construction.
It is “//”. So, someone, instead of
f3(f2(f1(x))))
can write
x // f1 // f2 // f3
It is in order of our natural speaking and thinking, and very easy to read and to edit. And have much less braces.
For adding the same to Scala 3, we need only one line.
extension [T](x: T) inline def \\[R](f: T => R) = f(x)
And it will work with all types without any overhead. And even, Tuple types will be automatically transformed to function’ multiple arguments. So, we can write not only
x \\ f1 \\ f2 \\ f3
but
list .
map(_ * 2) .
sum \\
(_ + 1) \\
println
or
def xyz(x: Int, y: Int, z: Int) = (x, y + z)
(1, 2, 3) \\
xyz \\
(_ + _) \\
factorial
We even can define logging function, like
def echo[T](x: T) = {println(x); x}
and easily add temporary log inside long chain-evaluation:
val res = 2 \\
(_ * 10) \\
echo \\
(_ / 2)
So, I suggest to add this very useful one line function to Predef:
extension [T](x: T) inline def \\[R](f: T => R) = f(x)
And, for symmetry, add
extension [T, R](f: T => R) inline def @:(x: T) = f(x)
…so someone can write function call chain without braces, like
f3 @: f2 @: f1 @: x