Kotlin overload resolution ambiguity in Pair with reference to println - kotlin

Using a reference to println as a Pair element fails when the reference is the first in the Pair.
>>> 0 to ::println
produces
(0, fun println(): kotlin.Unit)
but
>>> ::println to 0
gives
error: overload resolution ambiguity
Explicitly defining the pair using Pair() works fine in both cases.
What is the reason for this behaviour?

There are a couple of things going on here that you might find interesting.
Given that there's one version of println that takes no parameters, when you don't specify the type you expect ::println to be of, that's the version that's selected. [citation needed: I couldn't find any documentation/specification that says that this is the case, but that's what trying this out in Kotlin 1.2.71 shows]
The second piece is that the infix fun "to" is an extension method, so the type needs to be resolved before being able to invoke it.
For this reason, 0 to ::println gets automatically considered a Pair<Int, () -> Unit>.
To test this out, you can try the following:
fun foo(a: Int): Unit = Unit
fun foo(): Unit = Unit
val a = 0 to ::foo // the non-parameter version is selected
val b = ::foo to 0 // there's ambiguity. What extension method "to" to call?
val c: Pair<(Int) -> Unit, Int> = ::foo to 0 // No ambiguity, as I'm specifying the type
Now, if there are no overloads:
fun foo(a: Int): Unit = Unit
val a = 0 to ::foo // No ambiguity, there's only one to choose from
val b = ::foo to 0 // Same here, there's only one option
Finally, it gets interesting when you only have options WITH parameters:
fun foo(a: Int): Unit = Unit
fun foo(a: Int, b: Int): Unit = Unit
val a = 0 to ::foo // There's no non-parameter version to call, so there's ambiguity
val b = ::foo to 0 // there's ambiguity. What extension method "to" to call?

Related

Why does mapOf() with multiple types of keys return a Map with an `out` key parameter?

In Kotlin 1.7.0,
mapOf("s" to "s2", 0 to 5)
gives this response in the ki REPL:
res1: Map<out Any, Any> = {s=s2, 0=5}
My question is, why is the key parameter out (covariant)? Normally I might not care, but I'm trying to understand Kotlin generics, and specifically how variance works.
According to the docs, the signature for mapOf() is
fun <K, V> mapOf(vararg pairs: Pair<K, V>): Map<K, V>
I can understand that in order to cover both String and Int types, the K type parameter has to be Any. But why out? And why out for K and not for V?
If we try a mutable map, we get out for both:
mutableMapOf("s" to "s2", 0 to 5)
gives
MutableMap<out Any, out Any>
This makes even less sense to me. At least K is consistent with V in both being out. But now we can't add or change any of the mappings in our mutable map, because keys and values are both of a "producer" type:
val m2 = mutableMapOf("s" to "s2", 0 to 5)
[10] m2.put(3 to 6)
ERROR Type mismatch: inferred type is Pair<Int, Int> but Nothing was expected (Line_11.kts:1:8)
ERROR No value passed for parameter 'value' (Line_11.kts:1:14)
[15] m2[3] = "fi"
ERROR The integer literal does not conform to the expected type CapturedType(out Any) (Line_16.kts:1:4)
ERROR Type mismatch: inferred type is String but CapturedType(out Any) was expected (Line_16.kts:1:9)
We can fixed this by explicitly specifying the type parameters of our mutable map:
val m3: MutableMap<Any, Any> = mutableMapOf(3 to 4, "a" to "b")
But I'm wondering why these parameters in the inferred type are out. Is this intentional, or is it an unfortunate side effect of the generics system?
Update:
When I try something similar in the IDE, the out annotation is apparently not generated:
val myMap = mutableMapOf("s" to "s2", 0 to 5)
myMap[3] = 7
The IDE says the type of myMap is MutableMap<{Comparable*> & java.io.Serializable}, {Comparable*> & java.io.Serializable}>, as Tenfour04 also said in the comments. The ability to assign myMap[3] = 7 shows that the key is not annotated out. So I'm guessing that the out comes from something unique to the ki shell, or from Kotlin 1.7.0 (whereas the IDE seems to be running Kotlin 1.7.20).
Update 2:
I've now run this in a Kotlin scratch file in Android Studio (under Kotlin 1.7.20, on JVM). The following are local variables in main():
val m = mapOf("s" to "s2", 0 to 5)
printType(m)
val mm = mutableMapOf("s" to "s2", 0 to 5)
mm[3] = 7
printType(mm)
I'm using the printType() function that #broot linked to in comments:
import kotlin.reflect.typeOf
inline fun <reified T> printType(obj: T) {
println(typeOf<T>())
}
The results:
kotlin.collections.Map<out kotlin.Any, kotlin.Any>
kotlin.collections.MutableMap<out kotlin.Any, out kotlin.Any>
These are the same results I described at the beginning of the question.
This seems to me to show that the out annotation is not coming from something specific to the ki shell, nor from Kotlin 1.7.0.

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).

Smart cast of map access proven with `when in`

I’m trying to use Kotlin’s when block to look up an element in different maps. After confirming the element exists, the code subsequently does not smart-cast the resulting lookup in the map to not null.
Below is a minimum working example: is it possible to rework it such that !! is not needed?
fun main(args: Array<String>) {
val string = "abc"
val map1 = mapOf('a' to 5)
val map2 = mapOf('b' to 4)
when (val char = string.firstOrNull()) {
null -> println("Nothing to find")
in map1 -> println("Found in map1: ${map1[char]!!+1}")
in map2 -> println("Found in map2: ${map2[char]!!-1}")
else -> println("Unrecognised character $char")
}
}
Unfortunately, in Kotlin, functions can't have contracts of the form "if f returns true, then g doesn't return null." Hence, the compiler doesn't use information about definitely successful contains calls.
The workaround with !! is OK in this case because you can be sure that get returns not null. Implementation of complex patterns in when (KT-186) would cover this use case by allowing declaring a variable inside when clauses and providing static guarantees that it's not null.

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.