Why generic form of groupBy in Kotlin is not enough? - kotlin

Kotlin documentation for groupBy shows special form for every type, like ByteArray, IntArray. Why it is so, why the single generic form is not enough?
inline fun <T, K> Array<out T>.groupBy(
keySelector: (T) -> K
): Map<K, List<T>>
The snippet from Kotlin documentation
inline fun <T, K> Array<out T>.groupBy(
keySelector: (T) -> K
): Map<K, List<T>>
inline fun <K> ByteArray.groupBy(
keySelector: (Byte) -> K
): Map<K, List<Byte>>
inline fun <K> ShortArray.groupBy(
keySelector: (Short) -> K
): Map<K, List<Short>>
inline fun <K> IntArray.groupBy(
keySelector: (Int) -> K
): Map<K, List<Int>>
...
Question 2
It seems like IntArray is not subclassing the Array and that's probably the reason why it is necessary.
So, I wonder - if I would like to add my own function, let's say verySpecialGroupBy - does it means that I would also need to specify not just one such function - but repeat it for every array type?
Or it's a very specific and rare case when you would need to use those special arrays and in practice you can just define your function for generic Array and ignore the rest?

Those array specializations are for arrays of primitive types. So in your example of creating a verySpecialGroupBy function, you would only need to repeat it for each specialization if you wanted to use it with primitive type arrays.
You can read more about the need of primitive type array in this Kotlin discussion thread.

Related

Add Extension function in kotlin to all classes

Is it possible to add extension function to all classes? I was thinking about adding it to some common base class like Object. Is it possible?
With Kotlin, Any is the super type like Object for Java.
fun Any.myExtensionFunction() {
// ...
}
And if you want to support null-receiver too:
fun Any?.myExtensionFunction() {
// ...
}
It depends on whether you want to use the type of the object in the signature (either in another argument, or in the return type). If not, use Any(?) as Kevin Robatel's answer says; but if you do, you need to use generics, e.g. (from the standard library)
inline fun <T, R> T.run(block: T.() -> R): R
inline fun <T> T.takeIf(predicate: (T) -> Boolean): T?
etc.

Generic function in Kotlin

In Kotlin you can have a generic function like this:
fun <T> singletonList(item: T): List<T> {
// ...
}
I don't understand what the purpose of the <T> after the fun keyword is for. The function returns List<T>, so what is the point of <T>?
To be able to create a generic function the compiler must know that you want to work with diferent types. Kotlin is (like Java or C#) a strongly typed language. so just passing different types into a function will make the compiler mad.
To tell the compiler that a function should be accepting multiple types you need to add a "Type Parameter"
The <T> after fun is the definition of said "Type Parameter".
Which is then used at the item Argument.
Now the compiler knows that you'll specifiy the type of item when you make the call to singletonList(item: T)
Just doing
fun singletonList(item: T) : List<T> {[...]}
would make the compiler unhappy as it does not know T.
(As long as you don't have a class named T)
You also can have multiple "Type Params" when you separate them with commas:
fun <T, U> otherFunction(firstParam: T, secondParam: U): ReturnType
This is a generic function which, as per the language's syntax requirements, needs to provide this part <T>. You can use it to specify T further:
fun <T: Number> singletonList(item: T): List<T> {
// ...
}
It's also common to have multiple generic types:
fun <T: Number, R: Any> singletonList(item: T): R {
// ...
}

Calling a generic Java varargs method from Kotlin

I am trying to call the following Java method from Kotlin:
KStream<K, V>[] branch(final Predicate<? super K, ? super V>... predicates);
This method is part of the Kafka Streams API.
The way I tried to call it, following the Kotlin docs, was by defining an extension method:
fun <K, V> KStream<K, V>.kbranch(vararg predicates: (K, V) -> Boolean):
Array<KStream<K, V>> = this.branch(*predicates)
The problem is that it doesn't compile. I get the following error:
Type mismatch: inferred type is Array<out (K, V) -> Boolean>
but Array<(out) Predicate<in K!, in V!>!>! was expected
The similar KStream#filter method, which accepts a single Predicate as an argument, can be called without any issue when passing a Kotlin lambda with the same signature of (K, V) -> Boolean.
Any ideas? I have seen this similar question, but something here seems subtly different and I can't pinpoint it.
Unfortunately SAM conversion is not supported for variable length arguments. You can work around it though by converting the (K, V) -> Boolean to Predicate<K,V> yourself like so:
fun <K, V> KStream<K, V>.kbranch(vararg predicates: (K, V) -> Boolean): Array<KStream<K, V>> {
val arguments = predicates.map { Predicate { key: K, value: V -> it(key, value) } }
return this.branch(*arguments.toTypedArray())
}
Actually you can define like this.
fun <in K, in V> KStream<K, V>.kbranch(vararg predicates: out Predicate<K, V>):
Array<KStream<K, V>> = this.branch(*predicates)

In Kotlin, how do I idiomatically access nullable nested map values, or return a default?

Quick Kotlin best practices question, as I couldn't really work out the best way to do this from the documentation.
Assume I have the following nested map (typing specified explicitly for the purpose of this question):
val userWidgetCount: Map<String, Map<String, Int>> = mapOf(
"rikbrown" to mapOf(
"widgetTypeA" to 1,
"widgetTypeB" to 2))
Can the following mode be any more succinct?
fun getUserWidgetCount(username: String, widgetType: String): Int {
return userWidgetCount[username]?.get(widgetType)?:0
}
In other words, I want to return the user widget count iff the user is known and they have an entry for that widget type, otherwise zero. In particular I saw I can use [] syntax to access the map initially, but I couldn't see a way to do this at the second level after using ?..
I would use an extension operator method for that.
// Option 1
operator fun <K, V> Map<K, V>?.get(key: K) = this?.get(key)
// Option 2
operator fun <K, K2, V> Map<K, Map<K2, V>>.get(key1: K, key2: K2): V? = get(key1)?.get(key2)
Option 1:
Define an extension that provides get operator for nullable map. In Kotlin's stdlib such approach appears with Any?.toString() extension method.
fun getUserWidgetCount(username: String, widgetType: String): Int {
return userWidgetCount[username][widgetType] ?: 0
}
Option 2:
Create a special extension for map of maps. In my opinion, it is better because it shows the contract of the map of maps better than two gets in a row.
fun getUserWidgetCount(username: String, widgetType: String): Int {
return userWidgetCount[username, widgetType] ?: 0
}

Two functions with different number of type parameters in Kotlin

This two functions conflicts with each other.
Is there a workaround for this issue?
inline fun <reified T: Any> foo() = ...
inline fun <reified T: Any, reified I: Any> foo() = ...
Thanks!
Edit:
I found convenient(at least for me) solution for this issue:
inline fun <reified T: Any> foo() = foo<T, MyDefaultType>()
inline fun <reified T: Any, reified I: Any> foo(type1: KClass<T> = T::class, type2: KClass<I> = I::class) = ...
It can be even concise if you choose to add only one parameter.
Later you can use it like this:
val x = foo<A, B>()
val y = foo<C>()
That's what I need.
These functions have identical signatures from the compiler point of view. A type parameter is not part of a signature of a function; it can be inferred by the compiler automatically, and therefore does not serve to disambiguate calls to different overloads.
You need to assign different names to those functions.
Add the annotation #JvmName("foo2") to one of the functions.