Kotlin `with` with multiple params - kotlin

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()
}

Related

Passing a Tuple or Triple as parameters in 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)

Kotlin: iterate through array in reversed order

Is there a convenient way in Kotlin to iterate through an array, let's say IntArray, in reversed order with these 2 conditions:
do not create an additional reversed copy of the array.
I need a handle to an element like in Java's enhanced for.
The best I could get is adding an extension function, but this needs to be done for each type of array if I need it not only for IntArrays:
fun IntArray.forEachReversed(action: (Int) -> Unit): Unit {
for (i in indices.reversed()) action(this[i])
}
Is there a better way in Kotlin class library?
this needs to be done for each type of array if I need it not only for IntArrays:
I think this is unavoidable because of the way the JVM works. There are separate classes to represent each primitive type on the JVM. However, there are only 8 of them, so it shouldn't be too bad ;-)
For Collections, there is the asReversed() function, but it's not available for arrays:
val original = mutableListOf('a', 'b', 'c', 'd', 'e')
val originalReadOnly = original as List<Char>
val reversed = originalReadOnly.asReversed()
println(original) // [a, b, c, d, e]
println(reversed) // [e, d, c, b, a]
// changing the original list affects its reversed view
original.add('f')
println(original) // [a, b, c, d, e, f]
println(reversed) // [f, e, d, c, b, a]
To answer you question, you solution looks fine but if your are targeting primitive IntArray, LongArray, FloatArray etc you cannot come with a generic solution, as this classes are independent and only thing common is Iterator, but you cannot traverse the iterator in reverse order without making a copy(ListIterator supports reverse iteration though), but the closest you can get is to use Array<T> instead specific Array like below
fun <T> Array<T>.forEachReversed(action: (T) -> Unit){
for(i in indices.reversed()){ action(this[i]) }
}
val intArray = Array(2){ 0 }
val longArray = Array<Long>(2){ 0 }
intArray.forEachReversed { }
longArray.forEachReversed { }
As pointed out by #ajan.kali if you need primitive arrays there is not much you can do. I suppose you have to deal with arrays but, if this is not the case, you should prefer other data structures (more info here)
Returning to your question, if your are fine using generic arrays you could probably declare your iterator to iterate in reverse order:
class ReverseIterator<T>(val it: Iterable<T>) : Iterator<T> {
private var index = it.count() - 1
override fun hasNext() = index >= 0
override fun next(): T = try { it.elementAt(index--) } catch (e:
IndexOutOfBoundsException) { index -= 1; throw
NoSuchElementException(e.message) }
}
then your extension function will become:
fun <T> Iterable<T>.forEachReversed(action: (T) -> Unit) {
for(elem in ReverseIterator(this)) {
action(elem)
}
}
and then given an array you can invoke it this way:
intArrayOf(1, 2, 3).asIterable().forEachReversed {
println(it)
}
Not particularly happy with this, but with arrays there is not much you can do other to try avoiding them.

How to partition and typecast a List in Kotlin

In Kotlin I can:
val (specificMembers, regularMembers) = members.partition {it is SpecificMember}
However to my knowledge I can not do something like:
val (specificMembers as List<SpecificMember>, regularMembers) = members.partition {it is SpecificMember}
My question would be - is there's an idiomatic way to partition iterable by class and typecast it those partitioned parts if needed.
If you require that functionality more often, you may just reimplement the actual partition according to your needs, e.g.:
inline fun <reified U : T, T> Iterable<T>.partitionByType(): Pair<List<U>, List<T>> {
val first = ArrayList<U>()
val second = ArrayList<T>()
for (element in this) {
if (element is U) first.add(element)
else second.add(element)
}
return Pair(first, second)
}
with a usage similar as to follows:
val (specificMembers, regularMembers) = members.partitionByType<SpecificMember, Member>()
// where specificMembers : List<SpecificMember>
// and regularMembers : List<Member> for this example
Note that this way you can also set the second type to a more generic one. I leave that up to you whether this makes sense. At least this way an unchecked cast isn't necessary.
The alternative is also shown by Simon with the let-usage. You can also directly cast the result of partition (without let and another Pair) to whatever fits, e.g.:
val (specificMembers, regularMembers) = members.partition {it is SpecificMember} as Pair<List<SpecificMember>, List<Member>>
The partition function will return a Pair<List<T>, List<T>> with T being the generic type of your Iterable. You can transform the partitioned values again using e.g. let:
val (specificMembers, regularMembers) = lists
.partition { it is SpecificMember }
.let { Pair(it.first as List<SpecificMember>, it.second) }

What does "with" mean in Kotlin?

I've read the docs on it 3 times and I still have no idea what it does. Can someone ELI5 (Explain Like I'm Five) it please? Here's how I'm using it:
fun main(args: Array<String>) {
val UserModel = UserModel()
val app = Javalin.create().port(7000).start()
with (app) {
get("/users") {
context -> context.json(UserModel)
}
}
}
with is used to access an object's members and methods without having to refer to the object once per access. It is (mostly) for abbreviating your code. It is frequently used when constructing an object:
// Verbose way, 204 characters:
var thing = Thingummy()
thing.component1 = something()
thing.component2 = somethingElse()
thing.component3 = constantValue
thing.component4 = foo()
thing.component5 = bar()
parent.children.add(thing)
thing.refcount = 1
// Terse way, 182 characters:
var thing = Thingummy()
with(thing) {
component1 = something()
component2 = somethingElse()
component3 = constantValue
component4 = foo()
component5 = bar()
parent.children.add(this)
refcount = 1
}
The documentation says:
inline fun <T, R> with(receiver: T, block: T.() -> R): R (source)
Calls the specified function block with the given receiver as its receiver and returns its result.
The way I think of it is that it is calling a function (the block) where this in the scope of the block is the receiver.
Whatever the block returns is the return type.
Essentially calling a method where you provide the implicit this and can return any result from it.
Here is an example to demonstrate:
val rec = "hello"
val returnedValue: Int = with(rec) {
println("$this is ${length}")
lastIndexOf("l")
}
The rec in this case is the receiver of the function call - the this in the scope of the block. The $length and lastIndexOf are both called on the receiver.
The return value can be seen to be an Int because that is the last method call in the body - that is the generic type parameter R of the signature.
The definition of with:
inline fun <T, R> with(receiver: T, block: T.() -> R): R (source)
Actually it's implementation is straight forward: The block is executed on receiver, which works for any type:
receiver.block() //that's the body of `with`
The great thing to mention here, is the parameter type T.() -> R:
It's called function literal with receiver. It's actually a lambda that can access the receiver's members without any additional qualifiers.
In your example the context of with receiver app is accessed in that way.
Besides stdlib functions like with or apply, this functionality is what makes Kotlin great for writing Domain Specific Languages as it allows the creation of scopes within which you have access on certain functionalities.
val citizen2 = Citizen("Tom", 24, "Washington")
val age = with(citizen2) {
println("$name - $age $residence ")
age = this.age + age
residence = "Florida"
age+10 // returns 58
}
println("${citizen2.name} - ${citizen2.age} - $age - ${citizen2.residence} ")
data class Citizen(var name: String, var age: Int, var residence: String)
Output:
Tom - 24 Washington
Tom - 48 - 58 - Florida
Note that :
We can access age property of citizen(receiver object) with this.age or age
last line(age+10 in this example) in the lambda of with() returns.
With is used to apply several operations to an object or access object's methods e.g. in this example we are accessing String's capitalize() extension method
data class Person(val name:String)
fun main(){
val person = Person("john doe")
with(person) {
println(name.capitalize()) // output John Doe
}
}
Under the hood with is a higher-order function. Here we are saying with the Person name call capitalize ( ). We don’t actually need ‘this’ because it is implicit and can be removed

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.