4
\$\begingroup\$

In Kotlin comparison operators can be used instead of compareTo method:

a > b   // a.compareTo(b) > 0
a < b   // a.compareTo(b) < 0
a >= b  // a.compareTo(b) >= 0
a <= b  // a.compareTo(b) <= 0

It's convenient and makes comparisons a lot more readable. However, these operators cannot be used if there is no suitable compareTo method, but there is a suitable Comparator.

To make it possible to use them in this case, I've created a use extension function for a Comparator interface:

inline fun <T, R> Comparator<T>.use(block: ComparatorDSL<T>.() -> R) =
    ComparatorDSL(this).run(block)

Where ComparatorDSL is the following class:

inline class ComparatorDSL<T>(private val comparator: Comparator<T>) {
    operator fun T.compareTo(other: T) = comparator.compare(this, other)
}

Now I can use it like this:

comparator.use { a > b } // comparator.compare(a, b) > 0

Questions:

  • Is comparator.use { a > b } more readable than comparator.compare(a, b) > 0?
  • Is it a good idea to replace use with invoke operator or make this function infix?
  • Any improvement suggestions that you can think of
\$\endgroup\$
4
  • \$\begingroup\$ Like the idea. Only thing I don't like is the name. Use in my eyes refers to the Closeable- interface. Maybe check is better, or just compare? \$\endgroup\$
    – tieskedh
    Commented Nov 15, 2019 at 14:20
  • \$\begingroup\$ @tieskedh That's a good point. But check doesn't make much sense if you use it not for one comparison but wrap the whole function with it. Maybe it's better to remove the name completely and use the invoke operator. \$\endgroup\$ Commented Nov 17, 2019 at 11:27
  • \$\begingroup\$ I don't like that idea, as this implies that the main goal for the comparator is to function as an predicate, while I think sorting is as important as checking... \$\endgroup\$
    – tieskedh
    Commented Nov 18, 2019 at 13:05
  • \$\begingroup\$ I like the implementation for this use-case. The naming is always difficult, but I would suggest 1. 'test' as in Javas Predicate, or 2. 'isTrue' / 'isTrueFor' to indicate a boolean result \$\endgroup\$
    – Neo
    Commented Jan 9, 2020 at 7:31

1 Answer 1

1
\$\begingroup\$

Is comparator.use { a > b } more readable than comparator.compare(a, b) > 0?

Readability is relative and more a point of view. Usually something is considered more readable, the more people say it is.

In my personal opinion both solutions are easy to read, while I like the syntax of the first more. Actually something very similar exists in the language already: compareBy

list.sortedWith(
  compareBy{ it.a }.thenBy { it.b }.thenByDescending { it.c }
)

It has all combinations you need and provides a nice, well readable syntax.

Is it a good idea to replace use with invoke operator or make this function infix?

  1. use isntead of invoke

It is opinion based, just like readability. Its up to you and your team.

  1. Infix

Making a function an infix function is just another customisation option for your syntax. The only important thing to remeber is:

Infix function calls have lower precedence than the arithmetic operators, type casts, and the rangeTo operator. The following expressions are equivalent:

  • 1 shl 2 + 3 is equivalent to 1 shl (2 + 3)
  • 0 until n * 2 is equivalent to 0 until (n * 2)
  • xs union ys as Set<> is equivalent to xs union (ysas Set<>)

On the other hand, infix function call's precedence is higher than that of the boolean operators && and ||, is- and in-checks, and some other operators. These expressions are equivalent as well:

  • a && b xor c is equivalent to a && (b xor c)
  • a xor b in c isequivalent to (a xor b) in c

Kotlinlang.org

-

Any improvement suggestions that you can think of

Strongly consider to use compareBy like described before.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ compareBy gives great ways to create the comparators. The post uses the comparetors to create predicates, to get a boolean value. Therefor, it's not a replacement for compareBy, but an addition to the Compareable interfaces. I do like your explanation for infix-functions; This means that there aren't serious implications in this case. \$\endgroup\$
    – tieskedh
    Commented Nov 18, 2019 at 13:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.