Passing a Tuple or Triple as parameters in Kotlin - kotlin

I have a function in Kotlin that is something like this:
fun getSlots(year: Int, month: Int, day: Int) {
// some magic stuff, for example let's just print it
print("$year-$month-$day")
}
And I have another function that returns a Triple:
fun myMagicFunction(): Triple<Int, Int, Int> {
return Triple(2020, 1, 1)
}
I would like to call to the first function getSlots, using the return value of the second function myMagicFunction, without having to extract the members from the triple and pass them one by one. Something that in Python for example is possible by doing func(*args), but I don't know if it is possible in Kotlin.
Is it possible in Kotlin or do I have to go the slow way with this situation? Assume that modifying the previous two functions to return something else is not an option.

I can't find any simple way (hopefully it will be available some day in kotlin).
However you can write some helper infix function like this:
infix fun <T, U, S, V> KFunction3<T, U, S, V>.callWith(arguments: Triple<T, U, S>) : V = this.call(*arguments.toList().toTypedArray())
and then just simply call it:
::getSlots callWith myMagicFunction()
Of course you can add another one for Pair:
infix fun <T, U, V> KFunction2<T, U, V>.callWith(arguments: Pair<T, U>) : V = this.call(*arguments.toList().toTypedArray())
EDIT:
Thanks to #broot we have better solution:
infix fun <T, U, S, V> ((T, U, S) -> V).callWith(arguments: Triple<T, U, S>) : V = this(arguments.first, arguments.second, arguments.third)

Kotlin also has a spread operator (func(*args)), but currently it works only if the argument of func is declared as vararg (to avoid runtime exception if the size of args is not the same as func arity).
Just add one more code line with destructing declaration:
val (year, month, day) = myMagicFunction()
getSlots(year, month, day)

Related

How can I create a Map with non-null values from a set of nullable items in Kotlin?

In the Kotlin code, I want to add two fields to the map like this:
val myMap: Map<Type, List<Parameter>> = mapOf(
Pair(Type.POST, request.postDetails.postParameters),//postDetails can be nullable
Pair(Type.COMMENT, request.commentDetails.commentParameters)//commentDetails can be nullable
)
The above code is showing error at postDetails.postParameters and commentDetails.commentParameters because they can be nullable.
How can I create a map inplace like this instead of creating a variable and updating it where I want to keep the pair only in the case the value is not null?
I would just write my own factory methods for it, and call these methods instead.
fun <K, V> mapOfNullableValues(vararg pairs: Pair<K, V?>): Map<K, V> =
pairs.mapNotNull { (k, v) ->
if (v != null) k to v else null
}.toMap()
fun <K, V> mutableMapOfNullableValues(vararg pairs: Pair<K, V?>): MutableMap<K, V> =
pairs.mapNotNull { (k, v) ->
if (v != null) k to v else null
}.toMap(mutableMapOf())
By writing your own factory methods, you get to work with an array of Pairs, which is way easier than modifying the use site in place.
Note that compared to the built in builders, these methods create an extra list.
One way I found out without adding a lot of extra code would be to add code to add emptyList in the case it is null and remove them later.
Something like this:
val myMap: Map<Type, List<Parameter>> = mapOf(
Pair(Type.POST, request.postDetails?.postParameters ?: listOf()),
Pair(Type.COMMENT, request.commentDetails?.commentParameters ?: listOf())//commentDetails can be nullable
).filter{ it.value.isNotEmpty() }

Generic infix function with several upper bounds

I am trying to do this
infix fun Int.divBy (_denom: Int): Rational {
var num = this.toBigInteger()
var denom = _denom.toBigInteger()
// reduce result
val result = Rational(num, denom)
result.reduce()
// return
println("Returning: Rational $result")
return result
}
but for Long, Int and BigInteger, and without having to rewrite the same for all of them. I tried this, but I get an error:
infix fun <T> T.divBy (_denom: T): Rational where
T: Int, T:BigInteger, T: Long
{
....
}
So that things like val third = 1 divBy 3 can be done.
Error 1
I believe this is not possible, because there is no interface for "something convertable to BigInteger". Still, you can keep most of your code in a single function receiving BigInteger objects and provide multiple functions for just converting to BigInteger:
infix fun Int.divBy(denom: Int): Rational = toBigInteger() divBy denom.toBigInteger()
infix fun Long.divBy(denom: Long): Rational = toBigInteger() divBy denom.toBigInteger()
inline infix fun BigInteger.divBy (denom: BigInteger): Rational {
// reduce result
val result = Rational(this, denom)
result.reduce()
// return
println("Returning: Rational $result")
return result
}
Edit (#ademord): the final solution looks like this, after cleaning it up:
infix fun Int.divBy(denom: Int): Rational = toBigInteger() divBy denom.toBigInteger()
infix fun Long.divBy(denom: Long): Rational = toBigInteger() divBy denom.toBigInteger()
infix fun BigInteger.divBy (denom: BigInteger): Rational = Rational(this, denom).reduce()
As a side note, it can't be done with generics and upper bounds, because their main purpose is that the code inside the function knows what is the type of T. where clause is used to specify multiple requirements that T needs to satisfy altogether. Upper bounds are ANDed, not ORed. Note that if they would be ORed then we would still have to add runtime type checks and casts, which is exactly what we try to avoid providing upper bounds (thanks #Tenfour04 for pointing this out).

Kotlin `with` with multiple params

I really like how with behaves. Is it possible to extend with so it works with multiple params.
I want to use with like this.
with(foo, bar){
fooFunction()
barFunction()
}
First, I strongly against it.
One can come close to what you want:
data class A(val a: Int)
data class B(val b: Int)
fun<S, T> withPair(a: S, b: T, f: S.() -> T.() -> Unit) {
val g = a.f()
b.g()
}
fun main() {
withPair(A(1), B(2)) {{
print(a)
print(b)
}}
}
So you can have a block function which return a block function. You need nested lambdas though.
I don't think it's possible to write a function which behaves like this, but with the standard with you can write
with(foo) {
with(bar) {
fooFunction()
barFunction()
}
}
(note that if a method is available on both foo and bar, this way the bar method will be called).
Another possibility is to use a Pair, something like:
with( Pair("abc" , listOf(1,2,3)) ) {
println(first.plus("d"))
println(second.reversed())
}
Prints:
abcd
[3, 2, 1]
It's impossible to do this with the standard with function because it cannot have two receiver types of the lambda (accessed by this).
with(foo, bar){
fooFunction() //`this` would have to mean `foo`
barFunction() //`this` would have to mean `bar`
}
Nesting two withs is nasty. It can cause all sort of issues, with this ambiguity...
That said, you can create your own with function that will work similarly to the standard one, but will not use passed extension fun (so no receiver type "hidden" behind this), but a regular lambda with two arguments:
inline fun <T1, T2, R> with(t1: T1, t2: T2, block: (T1, T2) -> R): R {
return block.invoke(t1, t2)
}
//then:
with(foo, bar) { f, b ->
f.fooFunction()
b.barFunction()
}

Kotlin: Construct value of derived generic type in base class

I'm trying to reduce duplication across some vector types by defining the operators once, but I'm not sure it's possible. This seemed like the most promising approach:
open class VecN<Derived: VecN<Derived>>(val buffer: FloatArray) {
operator fun minus(other: Derived) = Derived(buffer.zip(other.buffer, { a, b -> a - b }).toFloatArray())
operator fun plus(other: Derived) = Derived(buffer.zip(other.buffer, { a, b -> a + b }).toFloatArray())
... many more operators...
}
class Vec2(x: Float, y: Float) : VecN<Vec2>(floatArrayOf(x, y))
class Vec3(x: Float, y: Float, z: Float) : VecN<Vec3>(floatArrayOf(x, y, z))
class Vec4(x: Float, y: Float, z: Float, w: Float) : VecN<Vec4>(floatArrayOf(x, y, z, w))
This gives me "Type parameter Derived cannot be called as function" where I try to construct my Derived return value.
Is it possible to achieve this in Kotlin?
You cannot do that in a straightforward way because, in Kotlin, you can only call a constructor of a concrete type, there's no way to call a constructor of a type parameter. Moreover, Kotlin does not allow passing an array into a function/constructor that expects fixed number of separate values.
However, you can try to achieve that without too much boilerplate using an abstract function, like this:
abstract class VecN<Derived: VecN<Derived>>(val buffer: FloatArray) {
protected abstract fun createNew(buffer: FloatArray): Derived
operator fun minus(other: Derived) =
createNew(buffer.zip(other.buffer, Float::minus).toFloatArray())
// ...
}
Then you have to override this function in each of the derived classes:
class Vec2(x: Float, y: Float) : VecN<Vec2>(floatArrayOf(x, y)) {
override protected fun createNew(buffer: FloatArray) = Vec2(buffer[0], buffer[1])
}
(demo of this code)

Function definition: fun vs val

I'm curious about what is the suggested way to define member functions in Kotlin. Consider these two member functions:
class A {
fun f(x: Int) = 42
val g = fun(x: Int) = 42
}
These appear to accomplish the same thing, but I found subtle differences.
The val based definition, for instance, seems to be more flexible in some scenarios. That is, I could not work out a straight forward way to compose f with other functions, but I could with g. To toy around with these definitions, I used the funKTionale library. I found that this does not compile:
val z = g andThen A::f // f is a member function
But if f were defined as a val pointing to the same function, it would compile just fine. To figure out what was going on I asked IntelliJ to explicitly define the type of ::f and g for me, and it gives me this:
val fref: KFunction1<Int, Int> = ::f
val gref: (Int) -> Int = g
So one is of type KFunction1<Int, Int>, the other is of type (Int) -> Int. It's easy to see that both represent functions of type Int -> Int.
What is the difference between these two types, and in which cases does it matter? I noticed that for top-level functions, I can compose them fine using either definition, but in order to make the aforementioned composition compile, I had to write it like so:
val z = g andThen A::f.partially1(this)
i.e. I had to partially apply it to this first.
Since I don't have to go through this hassle when using vals for functions, is there a reason why I should ever define non-Unit member functions using fun? Is there a difference in performance or semantics that I am missing?
Kotlin is all about Java interoperability and defining a function as a val will produce a completely different result in terms of the interoperability. The following Kotlin class:
class A {
fun f(x: Int) = 42
val g = fun(x: Int) = 42
}
is effectively equivalent to:
public class A {
private final Function1<Integer, Integer> gref = new Function1<Integer, Integer>() {
#Override
public Integer invoke(final Integer integer) {
return 42;
}
};
public int f(final int value) {
return 42;
}
public Function1<Integer, Integer> getG() {
return gref;
}
}
As you can see, the main differences are:
fun f is just a usual method, while val g in fact is a higher-order function that returns another function
val g involves creation of a new class which isn't good if you are targeting Android
val g requires unnecessary boxing and unboxing
val g cannot be easily invoked from java: A().g(42) in Kotlin vs new A().getG().invoke(42) in Java
UPDATE:
Regarding the A::f syntax. The compiler will generate an extra Function2<A, Integer, Integer> class for every A::f occurrence, so the following code results in two extra classes with 7 methods each:
val first = A::f
val second = A::f
Kotlin compiler isn't smart enough at the moment to optimize such kind of things. You can vote for the issue here https://youtrack.jetbrains.com/issue/KT-9831. In case you are interested, here is how each class looks in the bytecode: https://gist.github.com/nsk-mironov/fc13f2075bfa05d8a3c3
Here's some code showing how f and g are different when it comes to usage:
fun main(args: Array<String>) {
val a = A()
exe(a.g) // OK
//exe(a.f) // does not compile
exe { a.f(it) } // OK
}
fun exe(p: (Int) -> Int) {
println(p(0))
}
Where f and g are:
fun f(x: Int) = 42
val g = fun(x: Int) = 42
You can see that g is an object that can be used like a lambda, but f cannot. To use f similarly, you have to wrap it in a lambda.