Search code examples
javakotlinoperator-overloadingmutablelist

Indexed access operator overload for a MutableList member in Kotlin


This is my scenario, I have several MutableList members, the first for storing String (called sl) and the rest for Any (called objects, names, ...), and I need to access the values in the objects, names and the rest through 2 ways:

  1. sl through the index,
  2. objects, names and the rest through the string value stored in sl,

Maybe an example is more clear:

var tmpListItem = myStringList.sl[0]  // read only for the sl list

myStringList.objects["keyname"] = "keyvalue"  // write and read for the rest
var tmpObj = myStringList.objects["keyname"]

myStringList.names["keyname"] = "keyvalue"
var tmpName = myStringList.names["keyname"]

I have been trying to overload the indexed access operator for a MutableList, but I get this error:

Type mismatch: inferred type is String but Int was expected

This is my attempt so far:

data class StringList(val str: String) {
    val sl = mutableListOf<String>()
    val objects = mutableListOf<Any?>()
    val names = mutableListOf<Any?>()
    val values = mutableListOf<Any?>()
    val strings = mutableListOf<Any?>()

    public operator fun <E> MutableList<E>.set(k: String, value: Any?) {
        val t = sl.indexOf(k)
        objects[t] = value
    }
    operator fun <E> MutableList<E>.get(e: String): Any? {
        val t = sl.indexOf(e)
        return objects[t]
    }
}

Not sure if another implementation is more appropriate for my scenario, any suggestion is welcome.


Solution

  • TL;DR

    If you want to access them from outside, those operator fun shouldn't be extensions of MutableList.

    data class StringList(val str: String) {
        val sl = mutableListOf<String>()
        val objects = mutableListOf<Any?>()
    
        operator fun set(k: String, value: Any?) {
            val t = sl.indexOf(k)
            objects[t] = value
        }
        operator fun get(e: String): Any? {
            val t = sl.indexOf(e)
            return objects[t]
        }
    }
    

    Now you can use them like so:

    myStringList["keyname"] = "keyvalue"
    var tmp = myStringList["keyname"]
    

    Details

    There are few things which I'd like to point out here:

    1. Extensions functions declared inside a class can be accessed only in that class or in one of its subclasses, so you can still use your version (e.g. myStringList.objects["keyname"]) only if you are invoking that operator function inside StringList.

    2. I think you should handle the case in which indexOf() returns -1, otherwise the functions set and get will throw an out-of-bounds exception.

    3. If you can, consider to use a simple Map<String, Any> for your use case.