Symbolic Operators

Kotlin does not currently support the ability to define custom symbolic operators. Many functional languages like F#, Haskell, OCaml provide this functionality which can lead to considerably more concise code as well as the ability to define DSL within the context of the language. An example use cases would be something like this:

infix fun <IP, R> (() -> IP).forwardCompose(f: (IP) -> R): () -> R {
    return { f(this()) }
}

private val add5 = {(i: Int)-> i + 5 }
private val multiplyBy2 = {(i: Int)-> i * 2 }
val add5andMultiplyBy2 = add5 forwardCompose multiplyBy2 // add5 andThen multiplyBy2

The forward compose function would be significantly more concise if I could define it with symbol operators (">>") as such:

infix fun <IP, R> (() -> IP).>>(f: (IP) -> R): () -> R {
    return { f(this()) }
}

private val add5 = {(i: Int)-> i + 5 }
private val multiplyBy2 = {(i: Int)-> i * 2 }
val add5andMultiplyBy2 = add5 >> multiplyBy2 // add5 andThen multiplyBy2

Only being limited to the existing symbolic set, presents some challenges for general code readabily IMO. Would it be possible to add support for custom symbol operators definitions?

I just read through that thread, doesn’t look like there was ever any agreement regarding the forward pipe operator. Other than it’s another language feature that requires some modifications to the compiler and adds complexity for maintainers.

My post here is specifically not to introduce new operators to the core language, but to give developers the ability to define symbolic operators. Forward pipe is one example of an operator that is very handy.

Ok,
I try to answer.

Concise code is not a goal, you should prove that the example is more readable.

If it “doesn’t look like there was ever any agreement regarding the forward pipe operator”, than it should be hard to define custom ones.

Debate is on the other thread.

I don’t think this would be a good idea. There have been many situations where developers are confused about the precedence of inline functions (in context of binary infix functions) since there is no way of setting the precedence. That would also be true for custom operators but with far worse results as you would expect them to behave like operators. It’s easy to say all infix functions have the same precedence, but to force this for all custom operators would be problematic.
This feature would immediately lead to binary operators being added (if not to the stdlib than to a lot of other libraries) but without proper operator precedence. I don’t think this would end well.
That said if you can come up with a system to fix this (across multiple libraries) …

But even if problems like this could be overcome, I still don’t like this idea. Ok, maybe kotlin could do with binary operators and maybe even a pipe operator (even though I still don’t think it needs either), but a way to define random operators? I think it’s a bit overkill. Just imagine all math libraries adding dozens of operators for all random maths functions. Why not add ** for pow and while we are at it
for the square root and who knows what for random other functions. Ok, most sensible programers wouldn’t add most of those, but wouldn’t it be nice (just for this specific domain) to have this one thing as an operator instead of a function?
On main goal of kotlin is to be readable and I don’t think the ability to define custom operators helps in this regard. I know this is a bit over the top and more like a worst case by someone abusing the idea, but it explains why I don’t think it’s good.
Every operator is something new each programmer has to learn and unlike function names they don’t explain what they do.

Have you tried:

infix fun <IP, R> (() -> IP).`>>`(f: (IP) -> R): () -> R {
    return { f(this()) }
}

Note the backticks in the name of the function.

1 Like