Not nullable Mutable Map - kotlin

Java : 1.8.0_102
Kotlin: 1.0.4
I'm trying to create a map where you can do something like map["key"] += 5 similar to javascript.
Kotlin already has withDefault that solves one part of this, but map's get function still returns a nullable value, so i proceeded to make my own implementation of this inspired by withDefault
interface NonNullableMutableMap<K,V> : MutableMap<K,V> {
override fun put(key: K, value: V): V
override fun get(key: K): V
}
fun <K,V> MutableMap<K,V>.withoutNullValues(default: () -> V): NonNullableMutableMap<K, V> {
return NonNullableMapWrapper(this, default)
}
class NonNullableMapWrapper<K,V>(val map: MutableMap<K,V>, val default: () -> V) : NonNullableMutableMap<K,V> {
override fun put(key: K, value: V): V = map.put(key, value) ?: default()
override fun get(key: K): V {
val value = map.getOrPut(key, default)
return value
}
override val size: Int get() = map.size
override fun containsKey(key: K): Boolean = map.containsKey(key)
override fun containsValue(value: V): Boolean = map.containsValue(value)
override fun isEmpty(): Boolean = map.isEmpty()
override val entries: MutableSet<MutableMap.MutableEntry<K, V>> get() = map.entries
override val keys: MutableSet<K> get() = map.keys
override val values: MutableCollection<V> get() = map.values
override fun clear() {
map.clear()
}
override fun putAll(from: Map<out K, V>) {
map.putAll(from)
}
override fun remove(key: K): V {
return map.remove(key) ?: default()
}
}
I created the following unit test to test it
class NonNullableMapTest {
#Test
fun notNullableTest() {
val map = HashMap<String, Long>().withoutNullValues { 0 }
map["first"] += 10L
map["second"] -= 10L
assertThat(map["first"]).isEqualTo(10L)
assertThat(map["second"]).isEqualTo(-10L)
assertThat(map["third"]).isEqualTo(0L)
}
}
But i'm getting the following error when i run the test:
tried to access method kotlin.collections.MapsKt__MapsJVMKt.set(Ljava/util/Map;Ljava/lang/Object;Ljava/lang/Object;)V from class foo.bar.NonNullableMapTest
java.lang.IllegalAccessError: tried to access method kotlin.collections.MapsKt__MapsJVMKt.set(Ljava/util/Map;Ljava/lang/Object;Ljava/lang/Object;)V from class foo.bar.NonNullableMapTest
Any idea how to resolve this issue?

This looks like a bug to me. I recommend reporting it at Kotlin (KT) | YouTrack.
One way to workaround it is by explicitly defining set on your NonNullableMutableMap interface. e.g.:
interface NonNullableMutableMap<K, V> : MutableMap<K, V> {
override fun put(key: K, value: V): V
override fun get(key: K): V
operator fun set(key: K, value: V) {
put(key, value)
}
}

Regarding to the runtime error you get, there is currently a bug in how += operator gets compiled for inline MutableMap.set extension function: https://youtrack.jetbrains.com/issue/KT-14227
The workaround is not to use +=:
map["first"] = map["first"] + 10L

Related

Chaining property references and maintaining both the ability to read and write

Using a KMutableProperty1 to access a classes property works both as a getter and setter.
class BaseClass(
var baseInt: Int = 0,
var baseInnerClass: InnerClass = InnerClass()
)
class InnerClass(
var innerInt: Int = 0,
)
val target = BaseClass()
val kMutableProperty1b = (BaseClass::baseInt)
kMutableProperty1b.set(target, 4)
val baseInt = kMutableProperty1b.get(target)
To be able to access nested properties like
BaseClass::innerClass -> InnerClass:innerInt
I tried to up chain two kMutableProperty1 with
fun <A, B, C> ((A) -> B).chained(getter : (B) -> C) : (A) -> C = { getter(this(it)) }
With that, the inner properties can be read, but not set:
val chainedKMutableProperty = baseMutableProperty.chained(InnerClass::innerInt)
val innerInt = chainedKMutableProperty(target)
chainedKMutableProperty.set(target, 5) // Not available
In Swift something similar can be achieved using KeyPaths
let target = BaseClass()
let aKeyPath = \BaseClass.baseInt
target[keyPath: aKeyPath] = 4
let baseInt = target[keyPath: aKeyPath]
let bKeyPath = \BaseClass.baseInnerClass
let chainedKeyPath = bKeyPath.appending(path: \InnerClass.innerInt)
let innerInt = target[keyPath: chainedKeyPath]
target[keyPath: chainedKeyPath] = 5
How can I do the same in Kotlin - chaining property accessors and maintaining both the ability to read and write?
I don't think there is something like this already in Kotlin or Java stdlib. We can easily create it by ourselves, although I don’t think it is a good idea to stick to KProperty. This interface isn’t just a generic accessor interface. It is a very specific thing: a property of a class. And we don't deal with class properties here.
Instead, I suggest to create our own interfaces. Below is a simple POC:
fun main() {
val target = BaseClass()
val chainedProp = BaseClass::baseInnerClass chain InnerClass::innerInt
println(chainedProp.get(target))
chainedProp.set(target, 5)
// or
println(target[chainedProp])
target[chainedProp] = 12
}
operator fun <T, V> T.get(key: MyProperty<T, V>): V = key.get(this)
operator fun <T, V> T.set(key: MyMutableProperty<T, V>, value: V) = key.set(this, value)
infix fun <T, V, V2> KProperty1<T, V>.chain(next: KMutableProperty1<V, V2>): MyMutableProperty<T, V2> = asMyProperty() chain next.asMyProperty()
infix fun <T, V, V2> MyProperty<T, V>.chain(next: MyMutableProperty<V, V2>): MyMutableProperty<T, V2> = object : MyMutableProperty<T, V2> {
override fun get(receiver: T): V2 {
return next.get(this#chain.get(receiver))
}
override fun set(receiver: T, value: V2) {
next.set(this#chain.get(receiver), value)
}
}
fun <T, V> KProperty1<T, V>.asMyProperty(): MyProperty<T, V> = object : MyProperty<T, V> {
override fun get(receiver: T): V {
return this#asMyProperty.get(receiver)
}
}
fun <T, V> KMutableProperty1<T, V>.asMyProperty(): MyMutableProperty<T, V> = object : MyMutableProperty<T, V> {
override fun get(receiver: T): V {
return this#asMyProperty.get(receiver)
}
override fun set(receiver: T, value: V) {
this#asMyProperty.set(receiver, value)
}
}
interface MyProperty<in T, out V> {
fun get(receiver: T): V
}
interface MyMutableProperty<in T, V> : MyProperty<T, V> {
fun set(receiver: T, value: V)
}

Add a side-effect to a function in a generic way

How can I write a Kotlin generic function that takes a function as an argument and adds a side-effect to it? For instance,
fun something(one: Int, two: String): String { return "${one}, ${two}" }
fun somethingElse(arg: Array<String>): String { return "${arg}" }
val w1 = wrapped(::something)
w1(42, "hello")
val w2 = wrapped(::somethingElse)
w2(arrayOf("ichi", "ni"))
The following works for functions that take only a single parameter:
fun <A, R> wrapped(theFun: (a: A) -> R): (a: A) -> R {
return { a: A ->
theFun(a).also { println("wrapped: result is $it") }
}
}
To make this work with an arbitrary number of arguments, I'd need some construct that gives me the type of the argument list. Unfortunately, the Function generic can't be used since it takes only one parameter. The following does not compile:
fun <A, R> wrapped(theFun: Function<A, R>): Function<A, R> {
return { args: A ->
theFun(*args).also { println("wrapped: result is ${it}") }
}
}
Or maybe I could use varargs? Does not seem to work with lambdas. Or Kotlin reflection?
Solution using reflection:
class KFunctionWithSideEffect<R>(private val f: KFunction<R>, private val sideEffect: (R) -> Unit) : KFunction<R> by f {
override fun call(vararg args: Any?) = f.call(*args).also { sideEffect(it) }
override fun callBy(args: Map<KParameter, Any?>) = f.callBy(args).also { sideEffect(it) }
}
fun <R> wrapped(theFun: KFunction<R>, sideEffect: (R) -> Unit = { str -> println("wrapped: result is $str") }) =
KFunctionWithSideEffect(theFun, sideEffect)
Usage:
val w1 = wrapped(::something)
w1.call(42, "hello")
val w2 = wrapped(::somethingElse)
w2.call(arrayOf("ichi", "ni"))

How to nest multiple property delegates in Kotlin

I've come accross a case where I want to "chain" mutliple delegates (piping the output of one into the other).
This seems to be possible:
private val errorLogList by listSO(listOf<StateObject<Luxeption>>(), SODest.NONE, publicSOAccessRights())
val errorLog: StateObject<List<StateObject<Luxeption>>> by addToSet(errorLogList)
However, this does not look too well :). I'd like to do it in one line like this:
val errorLog: StateObject<List<StateObject<Luxeption>>> by addToSet(
listSO(listOf<StateObject<Luxeption>>(), SODest.NONE, publicSOAccessRights())
)
My question: Is this type of creating properties through delegates possible in Kotlin?
Here are both implementations of my delegates:
addToSet:
open class ChildSOReturner {
val set: Set<StateObject<*>> = setOf()
inline fun <reified T> addToSet(so: T) = object: ReadOnlyProperty<Any?, T> {
override operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
if (thisRef is T) {
set.plus(so)
return so
} else throw IllegalArgumentException()
}
}
}
listSo:
fun <O> listSO(
initialState: List<StateObject<O>>,
soDest: SODest,
soAccessRights: SOAccessRights
) = object : ReadOnlyProperty<Any?, StateObject<List<StateObject<O>>>> {
override operator fun getValue(thisRef: Any?, property: KProperty<*>): StateObject<List<StateObject<O>>> {
val meta = SOMeta(SOId(property.name), soDest, soAccessRights)
return StateObjectList(initialState, meta)
}
}
It turned out to be quite tricky, but possible (unless I am missing something, and it isn't tested but the idea should work):
fun <T, U, V> composeProperties(prop: ReadOnlyProperty<T, U>, f: (U) -> ReadOnlyProperty<T, V>) : ReadOnlyProperty<T, V> {
var props = mutableMapOf<Pair<T, KProperty<*>>, ReadOnlyProperty<T, V>>()
return object : ReadOnlyProperty<T, V> {
override operator fun getValue(thisRef: T, property: KProperty<*>): V {
val prop1 = props.getOrPut(Pair(thisRef, property)) {
f(prop.getValue(thisRef, property))
}
return prop1.getValue(thisRef, property)
}
}
}
And then to use
val errorLog: ... by composeProperties(listSO(...)) { addToSet(it) }

How to inherit MutableList in Kotlin?

I am trying to inherit MutableList, and add my own function to it. For example:
class CompositeJob : MutableList<Job> {
fun cancelAllJobs() {
for (job in this) {
job.cancel()
}
}
}
But I got the following error:
Class 'CompositeJob' is not abstract and does not implement abstract member
public abstract val size: Int defined in kotlin.collections.MutableList
How can I inherit MutableList, so I can use its original methods like add() and isEmpty(), and add my own one?
Thanks.
One option other answers don't mention is delegation:
class CompositeJob : MutableList<Job> by mutableListOf() {
fun cancelAllJobs() {
for (job in this) {
job.cancel()
}
}
}
is basically equivalent to
class CompositeJob : MutableList<Job> {
private val impl: MutableList<Job> = mutableListOf()
override fun size() = impl.size()
override fun add(x: Job) { impl.add(x) }
// etc for all other MutableList methods
fun cancelAllJobs() {
for (job in this) {
job.cancel()
}
}
}
MutableList is an interface - it doesn't implement any of its methods, just declares them. If you want to implement MutableList from scratch, you'll have to implement all 20 of its methods plus the size property, as your error already told you.
You can, however, subclass actual implementations of this interface, for example ArrayList or LinkedList:
class CompositeJob : ArrayList<Job>() {
fun cancelAllJobs() {
for (job in this) {
job.cancel()
}
}
}
Edit: If you're just looking to group coroutine Job instances, you should use a parent Job, a SupervisorJob, and CoroutineScope at this point, instead of collecting jobs like this manually.
Implementation of all the members is not the only way to achieve what you need.
An easier way is create an extension function like this:
fun MutableList<Job>.cancelAllJobs() {
this.forEach { it.cancel() }
}
Now you can call myList.cancelAllJobs() for every MutableList<Job> object.
As I have tested you need to make CompositeJob an abstract as error also suggest. After that, you can able to override add() and isEmpty() from MutableList
So your code looks like as below:
abstract class CompositeJob : MutableList<Job> {
override fun add(element:Job): Boolean
{
}
override fun isEmpty(): Boolean
{
}
}
If you want to avoid inheritance, or if the concrete class methods are marked final, then you can use composition and redirect all method calls which are not overridden. Here's a template:
class MyMutableList<T> : MutableList<T> {
private val list = mutableListOf<T>()
override val size get() = list.size
// MutableList<T>
override fun add(element: T): Boolean = list.add(element)
override fun add(index: Int, element: T) = list.add(index, element)
override fun addAll(elements: Collection<T>): Boolean = list.addAll(elements)
override fun addAll(index: Int, elements: Collection<T>): Boolean = list.addAll(index, elements)
override fun clear() = list.clear()
override fun remove(element: T): Boolean = list.remove(element)
override fun removeAll(elements: Collection<T>): Boolean = list.removeAll(elements)
override fun removeAt(index: Int): T = list.removeAt(index)
override fun retainAll(elements: Collection<T>): Boolean = list.retainAll(elements)
override fun set(index: Int, element: T): T = list.set(index, element)
// List<T>
override fun contains(element: T): Boolean = list.contains(element)
override fun containsAll(elements: Collection<T>): Boolean = list.containsAll(elements)
override fun get(index: Int): T = list.get(index)
override fun indexOf(element: T): Int = list.indexOf(element)
override fun isEmpty(): Boolean = list.isEmpty()
override fun iterator(): MutableIterator<T> = list.iterator()
override fun lastIndexOf(element: T): Int = list.lastIndexOf(element)
override fun listIterator(): MutableListIterator<T> = list.listIterator()
override fun listIterator(index: Int): MutableListIterator<T> = list.listIterator(index)
override fun subList(fromIndex: Int, toIndex: Int): MutableList<T> =
list.subList(fromIndex, toIndex)
}
...of course, this might add an additional layer of indirection, possibly affecting list performance with a slight overhead.

Kotlin Comparator Compilation Error in IntelliJ

Using Kotlin 1.2.41-release and given a List<Pair<Int, Int>>, the following code generates a compilation error in Intellij, although Gradle command line build works.
sortedWith(compareBy({ it.first }, { it.second }))
Cannot choose among the following candidates without completing type inference.
public fun <T> compareBy(vararg selectors: (???) -> Comparable<*>?): kotlin.Comparator<???> defined in kotlin.comparisons
public fun <T> compareBy(vararg selectors: (Pair<Int, Int>) -> Comparable<*>?): kotlin.Comparator<Pair<Int, Int>> defined in kotlin.comparisons
How can I fix this?
Edit:
edges
.map {
it.either.run {
val p = this
val q = it.other(this)
val min = min(p, q)
if (min == p) p to q else q to p
}
}
.sortedWith(compareBy({ it.first }, { it.second }))
.toList()
where, edges is Iterable<Edge>
class Edge(private val v: Int, private val w: Int, val weight: Double) : Comparable<Edge> {
val either: Int
get() = v
fun other(vertex: Int): Int {
return if (v == vertex) w else v
}
override fun compareTo(other: Edge): Int {
return weight.compareTo(other.weight)
}
override fun toString(): String {
return "Edge(v=$v, w=$w, weight=$weight)"
}
}