An Any question

I’ve created a generic interface and objects using that but I got compile errors that I don’t understand:

        val listBoolean: List<Boolean> = listOf<Boolean>()
        val listAny: List<Any> = listBoolean

        val mapString: Map<String, String> = mapOf()
        val mapAnyAny: Map<Any, Any> = mapString

        val parameterString: Parameter<String> = StringParameter // object StringParameter : Parameter<String> {}
        val parameterAny: Parameter<Any> = parameterString

The compiler likes the List<Any> but not the Map<Any,Any> or Parameter<Any> line. I have no clue why this is so.

Code can be found here: DavidH / AnyQuestion · GitLab

p.s. I’m not sure if this belongs here or in Language design…

This has to do with generic variance.

If you take a look at the List interface you can see that the generic type is marked as out, this means that E (the generic type) is only ever returned. The Kotlin compiler figures out that if List<Boolean> only produces Boolean it also only produces Any (since Boolean extends Any).

The Map interface has its V (value) type marked as out as well. But not its K (key) type, since it’s both accepted Map.get(key) and returned Map.keys. If a type is not marked with in or out, it’s considered invariant. The compiler won’t allow you to upcast or downcast generic invariant types. Thus, Map<String,String> -> Map<Any,Any> isn’t allowed.

3 Likes

Adding to above answer, consider this example:

val mapString: Map<String, String> = mapOf()
val mapAnyAny: Map<Any, Any> = mapString // assume this is possible

val item = mapAnyAny[2]

Map.get() function of mapString was supposed to receive keys of type String. But we just provided Int to it. As a result, this cast is not really type-safe.

Note it is possible to cast mapString to Map<String, Any> - this is save, because when we acquire String values from the map, each String is at the same Any.

1 Like

Thanks, much clearer now. I appreciate the fast response.