2

Recently I was working with lists in kotlin and had the following snippet:

a = listOf(1, 2, 3, 4)
println(a[-2])

Of course this causes an IndexOutOfBoundsException so I thought it would be nice to extend this functionality. So I thought one could override the get operator in the List class:

operator fun <T> List<T>.get(index: Int): T =
        // Here this should call the non-overridden version of
        // get. 
        get(index % size)

I understand that extensions are just static methods and therefore cannot be overridden, but is there a way one can achieve something like this?

Of course you could just create another function

fun <T> List<T>.safeGet(index: Int): T = get(index % size)

but I'd like to know if there are other ways.

(I understand that index % size is a very naive way of doing what I want, but it's not the focus of my question and makes the code smaller.)

EDIT

When I wrote this question I thought the % operator would return always positive numbers when the right hand side is positive - like in python. I'm keeping the original question here just for consistency.

Fred
  • 16,367
  • 6
  • 50
  • 65

2 Answers2

3

Since get operator is already defined in List, you cannot redefine get (with one Int parameter). However, you can override invoke operator, which is not defined in List.

fun main(args: Array<String>) {
    val a = listOf(1, 2, 3, 4)
    println(a(-2))
}

// If `index` is negative, `index % size` will be non-positive by the definition of `rem` operator.
operator fun <T> List<T>.invoke(index: Int): T = if (index >= 0) get(index % size) else get((-index) % (-size))

although I think that creating a new extension method to List with an appropriate name will be more preferable option.

As a sidenote, (positive value) % (negative value) is non-negative, and (negative value) % (positive value) is non-positive.
% in Kotlin corresponds to rem in Haskell in the following example: https://stackoverflow.com/a/28027235/869330

Naetmul
  • 14,544
  • 8
  • 57
  • 81
2

You're trying something impossible, because extensions are always shadowed by members, even @JvmName cannot save you.

Workaround: use your second solution, or add a Unit parameter which is ugly (looks like a[x, Unit]) but can exist with its own get method together.

Another solution: create your own List implementation (recommended).

ice1000
  • 6,406
  • 4
  • 39
  • 85