Nate Jenson
Nate Jenson

Reputation: 2794

How to assign generic map as super class in kotlin

I'm wondering how to correctly use the in/out variance modifiers in this particular case.

I have a generic Map with a specific implementation type and I'd like to assign it to a variable under a more generic type:

var generalMap: Map<SimpleExpression<Any>, Any> = emptyMap()
var specificMap: Map<StringExpression, String?> = makeSomeMap()

generalMap = specificMap // this assignment won't compile :(

Also, StringExpression extends SimpleExpression<String>. I've tried monkeying with the out variance modifier a few different ways on the generalMap definition:

var generalMap: Map<out SimpleExpression<Any>, out Any?> = emptyMap()

...but unfortunately ran into the same compiler error.

Upvotes: 1

Views: 667

Answers (2)

hluhovskyi
hluhovskyi

Reputation: 10106

Such assignment is only possible if SimpleExpression<T> only produces T value. If so, make your interface or class declaration as following:

interface SimpleExpression<out T> 

The next thing you have to change it is declaration of generalMap. Add out variance to SimpleExpression<..> and make Any nullable:

var generalMap: Map<out SimpleExpression<Any>, Any?> = emptyMap()

After that compiler allows you to assign specificMap to generalMap safely.

In case if T in SimpleExpression is produced and consumed as well (has methods like fun consume(t: T) and fun produce(): T) then you should make your declaration of generalMap like this:

var generalMap: Map<out SimpleExpression<*>, Any?> = emptyMap()

Upvotes: 2

ephemient
ephemient

Reputation: 204698

Map is not variant on the key type, as it occurs both in in position to .get() and out position from .keys(). It's not safe to treat it as out because

var specificMap: Map<StringExpression, String?> = makeSomeMap()
var generalMap: Map<SimpleExpression<Any>, Any> = specificMap
generalMap[intExpression]  // specificMap.get(not a StringExpression)

That being said, there is nothing stopping you from making an unchecked cast if you believe this does not cause any actual problems with the specific Map implementation returned by makeSomeMap().

Upvotes: 2

Related Questions