How to get a handle on the binary operator functio...
# getting-started
d
How to get a handle on the binary operator functions like
==
,
>
, etc.? For "normal" functions I would use
::
but not sure how to do that for these operators. I want to convert user input (as string) to the operator function and then call this function on the provided values.
l
All operators have a function name, so you can use that.
1::plus
works if you specify which plus. It does require that the operator is defined for the type.
r
==
->
equals
>
->
compareTo
l
See here for list of names
💡 1
r
(tip: if you're using IntelliJ, you can use the
go to implementation
feature to look this up via your IDE)
1
d
I already tried
::equals
but that gives me only a single parameter function.
l
::equals
is a single argument function - it compares the receiver to the argument. 😄
r
Copy code
val instanceEquals: KFunction1<Any?, Boolean> = "My string"::equals

val stringEquals: KFunction2<String, Any?, Boolean> = String::equals
👍 2
l
T.equals(Any)
is the general signature for the equals method, where in this case T means a type.
d
So to obtain a boolean function for comparison I probably can't use simple reflection
::
, right? Instead, I would have to do something like
{ x: T, y: T -> x.compareTo(y) > 0 }
l
You can use x::compareTo to get the method.
d
yeah, but that doesn't return boolean
l
I see. You’d have to define one or use the lambda you provided.
You could define
T.compareToAsBoolean(y: T) -> Boolean
, but with better #naming
d
Hmm, but thanks to this intended usage of comparison the end result is quite verbose, e.g.
Copy code
val valueCompareTo = it.value.toBigDecimal()::compareTo
            return when (it.operator) {
                FilterOperator.EQUAL -> { money: MoneyDto -> valueCompareTo(money.amount) == 0 }
                FilterOperator.GREATER_THAN -> { money: MoneyDto -> valueCompareTo(money.amount) > 0 }
                FilterOperator.GREATER_THAN_OR_EQUAL -> { money: MoneyDto -> valueCompareTo(money.amount) >= 0 }
                FilterOperator.LESS_THAN -> { money: MoneyDto -> valueCompareTo(money.amount) < 0 }
                FilterOperator.LESS_THAN_OR_EQUAL -> { money: MoneyDto -> valueCompareTo(money.amount) <= 0 }
                else -> error("operator ${it.operator} not supported here")
            }
Ideally, I would like to return only the operator from the when expression and inject that into the money lambda (defined at single place only), but since there's no such thing as a comparison function that returns boolean I have to repeat that code. Or... ?
r
a function like
isGreaterThan
needs to be defined somewhere, in that case. You can choose to put it in the
when
expression, in the
MoneyDto
(if you have control over it), or define it as an extension function, for example
2
d
I see. My original thoughts perhaps were that this function surely must already be defined somewhere because
Copy code
fun <T> isGreaterThan(a: T, b: T) = a.compareTo(b) > 0
seems to be quite generic 🙂
Oh, this apparently can't be defined in a generic way 😞
l
What do you mean?
Copy code
fun <T: Comparable<T>> isGreaterThan(a: T, b: T) = a.compareTo(b) > 0
You didn’t specify that T has to be comparable.
👍 1
d
Anyway, isn't it reasonable to expect these functions to be in the stdlib?
l
I’d say no. The stdlib is included with all projects, so adding something should be an important change. The current Int behavior is consistent with the Java Comparable that exists, and provides more information (can tell you how much bigger or smaller if implemented that way).
The size of the stdlib is currently a major blocker for K/N on embedded systems. The stdlib alone creates a binary too big for most embedded systems.
d
I don't expect the current operators to be replaced. Just that those generic binary functions are added exactly for cases like mine.
I hear the binary size argument, although I'm not sure how those six small functions compare with the quite rich collections class (which of course I'm happy to use in my BE projects)
l
You can create a proposal for it to be added, but do keep in mind that you may only need 6 methods, but someone else may have another few methods that make sense for them, and someone else has another few methods they want.
I’d imagine somewhere there’s a third party library that brings in these useful helpers (kind of like arrow with functional methods). This keeps the stdlib small, while allowing methods to be added easily.
d
Anyway, I'm still struggling even to use these binary functions 😞 My hope was something like this:
Copy code
val filteredValue = it.value.toBigDecimal()
val cmp = filteredValue::isEqualTo
Apparently, that's not how it's supposed to be...
l
If you want to use
foo::isEqualTo
, you have to make sure the signature is
T.isEqualTo(other: T) -> Boolean
. If it’s like your greater than method above, you defined
isEqualTo(x: T, y: T) -> Boolean
, which is different.
d
I see now, of course...
l
Without the receiver, it’s just
::isEqualTo
d
I originally wanted to use just
::isEqualTo
and assign it to val but that's not possible without specifying the
T
. Will consider the other option (extension functions)
I guess there's no shorthand syntax for partial function application in Kotlin.
l
I’m sure if you specified a type for the val, it could get it.
d
Sure ^, I meant if there's a nice (without writing the full lambda) way how to get from two arg
isEqualTo
to single arg
isEqualTo
(with fixed first arg).