Cast with Generics, how to achieve this?


#1
data class Message (var code: String, var msg: String, var data: Any) {
    fun addDataItem(dataItem: Any): Message {
        if (this.data is Collection<*>) {
            this.data = this.data as Collection<*> + dataItem  // ok, but as-operation is essential
            return this
        }
        return this.copy(data = listOf(dataItem))
    } 

   fun addDataEntry(name: String, value: Any): Message {
        if (this.data is Map<*, *>) { // can reified to Map<String,Any> ?
          this.data = this.data as Map<*, *> + (name to value)  // compiler error here
        }

       return this.copy(data = mapOf(name to value))
    }
}

the map operation in the fun addDataEntry() is simple, but I can’t figure out the right way to achieve.
Thanks, forward


#2

Map<*, *> is equivalent to Map<out Any?, out Any?> — an out-projection of the Map<K, out V> interface which is invariant on its K type parameter. And plus operator function expects the invariant Map<K, out V>.

So currently you need to cast the map to be invariant on its key as following:

this.data = this.data as Map<Any?, *> + (name to value)

This is unsafe cast, so you get a warning, but in this situation you can safely ignore or suppress it.

This seems to be unneeded limitation of the plus operator, and I believe we could fix it by making plus accept Map<out K, out V> as its receiver. I’ve opened an issue KT-11301.