Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to map datatype to set of that datatype

Tags:

types

kotlin

The code:

abstract class DataContainer(public val path: String)
val preloaded: MutableMap<Class<out DataContainer>, HashSet<out DataContainer>> = hashMapOf()

I would like to know how to make Kotlin realize that the first out DataContainer is the same type as the second out DataContainer.
So that code like:

fun <D: DataContainer> get(clazz: Class<D>): HashSet<D> = preloaded[clazz] as HashSet<D>

Doesn't require as HashSet<D> (and isn't prone to casting errors). I am new to Kotlin, so do link documentation if I've missed something. Also, this code would be inside an object if it matters.

like image 314
EmmanuelMess Avatar asked Feb 24 '18 03:02

EmmanuelMess


1 Answers

I don't think that what you want is feasible at a language level.

A cast in the get method isn't that bad as long as you can do it safely. The only way I can see to do that safely is to control the put method as well.

If you enforce that each key of type D : DataContainer will be paired with a key of type Set<D>, you can safely cast when getting. For instance you could something like this:

object DataContainerRegistry {

    private val preloaded: MutableMap<Class<out DataContainer>, HashSet<DataContainer>> = hashMapOf()

    fun put(dataContainer: DataContainer) {
        val set = preloaded.getOrDefault(dataContainer::class.java, HashSet())
        set.add(dataContainer)
        preloaded[dataContainer::class.java] = set
    }

    fun <D : DataContainer> get(clazz: Class<D>) = preloaded.getOrDefault(clazz, HashSet()) as Set<D>

}

The limitations of this method are:

  1. only one class (DataContainerRegistry singleton in my example) will have direct access to the preloaded map
  2. the get method will return only Set, not the mutable interface.

This way you know that nobody will mess up preloaded and each Set contained in it, and you can then cast light-heartedly.

like image 184
lelloman Avatar answered Oct 03 '22 06:10

lelloman