Photo by Victoria Strukovskaya on Unsplash

Kotlin functions: %, rem and mod

Alex Vanyo

--

This is a short article I’m writing in 2022 for my future self, because I keep forgetting the difference between these functions and their precise behavior. Maybe you’ll also find it useful!

TL;DR for modern Kotlin (version 1.5 and later):

  • % is the same as rem, mod is different
  • %/rem will return 0 or a value with the same sign as the dividend
    (number “on the top” of the fraction)
  • mod will return 0 or a value with the same sign as the divisor
    (number “on the bottom” of the fraction)
  • someList[n % someList.size] can throw IndexOutOfBoundsException (if n is negative)

Runnable example of the matrix of options:

The reason why I’m writing this article (and why I personally keep getting confused) is that this behavior was not always the case, as is revealed if you search the web for mod vs rem behavior in Kotlin or change the version of Kotlin in the playground above. The history here also reveals how long it takes to fundamentally redefine what a function does.

In the beginning (of Kotlin), % was the same as the operator function mod, and it had the same behavior that % and rem have today.

In Kotlin 1.1, the operator function mod was deprecated with the replacement of rem (commit). At this point, all 3 functions had the same behavior which matches the behavior of % and rem today… at least for built-in operations on numbers. Since % is a special operator function, the language version of Kotlin you were targeting impacted whether mod or rem was actually called (this would be extremely important for a custom implementation with operator overloading)

In Kotlin 1.3, the deprecation level for the operator function mod was raised from a warning to an error (commit).

This set the stage for Kotlin 1.4, which removed mod completely for the numeric types (commit).

After they were removed for a full release, Kotlin 1.5 added new mod functions for numeric types, finally resulting in the same behavior that we have today (commit). Most notably, the new mod behaves differently than %/rem as showcased above, and therefore differently from the original mod function as well. I also want to specifically call out this commit for greatly clarifying the docs of rem and mod.

And that brings us to the present day! If this is your first time stumbling upon these two functions with similar names and functionality, hopefully this helps explain the behavior you can expect from any recent Kotlin code, and how we got to where we are now.

--

--