Goal: lazy map (where we only need the getter) sup...
# codereview
m
Goal: lazy map (where we only need the getter) supporting multithreaded access. Is there a better way?
Copy code
val getValuesForKey: (String) -> Set<String> =
    object : (String) -> Set<String> {
        val map = mutableMapOf<String, Set<String>>()

        override fun invoke(key: String): Set<String> =
            synchronized(this) {
                map.getOrPut(key) {
                    calculateValuesForKey(key)
                }
            }
    }
e
https://wiki.sei.cmu.edu/confluence/plugins/servlet/mobile?contentId=88487798 if you do have to use traditional Java locking, use a private lock to avoid other callers from interfering
but I would both lean on existing functionality to build the map as well as use per-key locking,
Copy code
class Memo<K, V>(
    val block: (K) -> V,
) : (K) -> V {
    private val cache: ConcurrentMap<K, Lazy<V>> = ConcurrentHashMap()
    override fun invoke(key: K): V =
        cache.computeIfAbsent(key) { lazy { block(it) } }.value
}
m
Thanks, though I was hoping to just use kotlin standard library
e
synchronized is JVM-only so you're not losing any portability by using java.util.concurrent
m
I’m curious, why would
synchronized
be added to the standard lib, when it’s JVM-only?
e
quite a few parts of kotlin-stdlib are JVM-only, it's marked in the documentation. (there's also JS-only and native-only parts as well)
for example,
.toSortedSet()
and
.toSortedMap()
are also JVM-only,
console
and
.unsafeCast()
are JS-only,
Char.toChars()
and
getTimeMicros()
are native-only
there's also parts that of kotlin-stdlib that are only on specific JVM versions, such as
.use()
on Java 7+ and
.asStream()
on Java 8+
in the case of
synchronized
, there's no other way to get the same access to that functionality of the JVM without compiler support, but it doesn't make any sense in JS (which is single-threaded) and the mechanisms on native are incompatibly different, so it's JVM-only
🙏 1