Extension function with type Any

I was trying to write a more generic extension function which counts elements of all lists in a map:

So, instead of

val Map<Int, List<Vertex>>.listElementCount: Int
    get() {
        var total = 0
        for (list in this.values) { total += list.size}
        return total
    }

I would like to write as I then could apply it to all Maps with a List of values

val Map<Any, List<Any>>.listElementCount: Int
    get() {
        var total = 0
        for (list in this.values) { total += list.size}
        return total
    }

This would even be better:

val Map<Any, Collection<Any>>.listElementCount: Int
    get() {
        var total = 0
        for (list in this.values) { total += list.size}
        return total
    }

Unfortunately, these extension functions are not recognized.

Is that something Kotlin could pick up in the future?

This question has possibly been asked before, forgive me I could not find it that specific.

Can you explain this a bit better? Do you get an error message? If so, what error message?

The issue seems to be with the first ‘Any’ in the Map
I get the following compilation error:

Unresolved reference. None of the following candidates is applicable because of receiver type mismatch:
public val Map<Any, List<Any>>.listElementCount: Int defined in root package in file TestExtensionFunction.kt
public val Map<Int, List<Any>>.listElementCount: Int defined in root package in file TestExtensionFunction.kt
class TestExtensionFunction {

    val myMapDouble = mutableMapOf<Int, List<Double>>()
    val myMapString = mutableMapOf<Int, List<String>>()
    val myMapStringString = mutableMapOf<String, List<String>>()

    init {
        myMapDouble[1] = listOf(2.0,2.3)
        myMapDouble[2] = listOf(5.0,5.1)

        myMapString[1] = listOf("my", "first", "entry")
        myMapString[2] = listOf("my", "second", "entry")

        myMapStringString["1"] = listOf("my", "first", "entry")
        myMapStringString["2"] = listOf("my", "second", "entry")

        println("myMapDouble contains ${myMapDouble.listElementCount} elements")
        println("myMapString contains ${myMapString.listElementCount} elements")
        println("myMapString2 contains ${myMapStringString.listElementCount} elements") // does not compile

    }

}

val Map<Int, Collection<Any>>.listElementCount: Int
    get() {
        var total = 0
        for (list in this.values) { total += list.size}
        return total
    }

val Map<Any, List<Any>>.listElementCount: Int
    get() {
        var total = 0
        for (list in this.values) { total += list.size}
        return total
    }

Update: I found out it works when i define it with ‘out Any’, but I have no clue why it would require out in this case:

val Map<out Any, Collection<Any>>.listElementCount: Int
    get() {
        var total = 0
        for (list in this.values) { total += list.size}
        return total
    }

By using Any we mean we require a collection of Any specifically. If we don’t care about the type, we should use * instead:

val Map<*, Collection<*>>.listElementCount: Int

BTW, it could be even Iterable.

3 Likes

* works great.

Iterable not, since it does not have size property.

Ahh, right, sorry, I answered too quickly :slight_smile: