How to force Kotlin to call a particular overloaded method in Java interface? - kotlin

There is a Java interface
interface MyContract {
<M> void execute(Class<M> argClass, Consumer<M> action);
<M, R> R execute(Class<M> argClass, Function<M, R> action);
}
When execute method is called from Kotlin code by default compiler always uses the first overloaded method, even when the expected type was explicitly set, there is a compilation error:
MyContract myContract = createSomehow();
val x: Int = myContract.execute(SomeClass::class.java, { it -> 1})
Compilation error:
Type mismatch: inferred type is Unit but Int was expected
To force compiler use the second overloaded method I add this boilerplate:
val fn: (SomeClass) -> Int = { it -> 1 }
val x: Int = myContract.execute(SomeClass::class.java, fn)
What is a normal syntactical way to express intention to call a particular overloaded method in this case?

This problem is not java-interop specific, if a similar interface was defined in Kotlin, the error would be the same. Looks like there is room for an overload resolution mechanism enhancement.
For a workaround you may use the fact, that overloaded methods have a different amount of type parameters, so you may specify them explicitly:
val x = myContract.execute<SomeClass, Int>(SomeClass::class.java) { it -> 1 }
This is still noisy, so I'd suggest declaring Kotlin-specific API:
internal inline fun <reified M> MyContract.execute(noinline action: ((M) -> Unit)?) = execute(M::class.java, action)
internal inline fun <reified M, R> MyContract.execute(noinline action: ((M) -> R)?) = execute(M::class.java, action)
Now it may be called with:
val x = myContract.execute<SomeClass, Int> { it -> 1 }

Related

Make class extend multiple function type interfaces with the same signature in Kotlin

I want to make a class extend multiple function type interfaces.
This works since the function types have different signatures, () -> Unit and (String) - Unit
typealias A = () -> Unit
typealias B = (something: String) -> Unit
class Test : A, B {
override fun invoke() {
TODO("Not yet implemented")
}
override fun invoke(something: String) {
TODO("Not yet implemented")
}
}
Now if I add a third function type, the compiler complains about Conflicting Overloads or A supertype appears twice
typealias A = () -> Unit
typealias B = (something: String) -> Unit
typealias C = (somethingElse: String) -> Unit
class Test : A, B, C {
override fun invoke() {
TODO("Not yet implemented")
}
override fun invoke(something: String) {
TODO("Not yet implemented")
}
override fun invoke(somethingElse: String) {
TODO("Not yet implemented")
}
}
I can obviously go and add garbage params to C to make it work, but this seems more like a hack
typealias C = (somethingElse: String, garbage: Unit?) -> Unit
but now if I define type D with the same signature,
typealias D = (somethingElseElse: String, garbage: Unit?) -> Unit
I would run into the same issue.
I thought that maybe value classes could help here:
#JvmInline
value class BString(val value: String)
#JvmInline
value class CString(val value: String)
typealias A = () -> Unit
typealias B = (something: BString) -> Unit
typealias C = (somethingElse: CString) -> Unit
class Test : A, B, C {
override fun invoke() {
TODO("Not yet implemented")
}
override fun invoke(something: BString) {
TODO("Not yet implemented")
}
override fun invoke(somethingElse: CString) {
TODO("Not yet implemented")
}
}
... but since value classes are compiled out of existence, that too is not a solution
Platform declaration clash: The following declarations have the same
JVM signature (invoke(Ljava/lang/Object;)Ljava/lang/Object;):
I'm assuming Kotlin KEEP 302, Binary Signature Name (https://github.com/Kotlin/KEEP/blob/binary-signature/proposals/multiplatform/binary-signature.md), would solve this issue in the future, but what is the correct way in the meantime to implement multiple function interfaces with the same signatures?
Practical use-case that I can think of: let's say you want to have a class that can handle Clickable and DoubleClickable, both would have something like (Event) -> Unit
EDIT: based on #mateusz's answer, this works, but only when using value classes, not if interface B and C are using normal Strings:
#JvmInline
value class BString(val value: String)
#JvmInline
value class CString(val value: String)
interface A {
operator fun invoke()
}
interface B {
operator fun invoke(something: BString)
}
interface C {
operator fun invoke(somethingElse: CString)
}
class Test : A, B, C {
override operator fun invoke() {
println("invoke A")
}
override operator fun invoke(something: BString) {
println("invoke B - something = $something")
}
override operator fun invoke(somethingElse: CString) {
println("invoke C - somethingElse = $somethingElse")
}
}
fun main(args: Array<String>) {
val handlerA = A::invoke
val handlerB = B::invoke
val handlerC = C::invoke
val t = Test()
handlerA(t)
handlerB(t, BString("hello B"))
handlerC(t, CString("hello C"))
}
outputs:
invoke A
invoke B - something = BString(value=hello B)
invoke C -somethingElse = CString(value=hello C)
The completer does not care about parameter's names.
The fun test(a: String): String and fun test(b: String): String are the same functions. When you will call test("some") then which function should be called?
You can create dedicated interfaces:
interface Clickable {
fun click(param: String)
}
interface DoubleClickable {
fun fastDoubleClick(param: String)
fun slowDoubleClick(param: String)
}
Then you can use function references if you want val handleClickFun: String -> Unit = Clickable::click
This will never work. At the fundamental JVM level, you can't implement the same interface twice with different generics. I would not expect this to ever work, even with the KEEP you mention.
Why do you want to extend function interfaces at all? If you just want the nice call syntax, you can have separate operator fun invoke overloads, without overriding anything. But even better would be using functions with actual names. If you need to pass it to methods accepting lambdas, use method references, e.g. Test::handleClick and Test::handleDoubleClick.
A typealias is just a way to give a convenient label to a specific type - it's not a type in itself, anywhere you specify that typealias, you can can just pass in a variable defined as the real type, or any other typealias you've derived from it.
So B and C are the same thing. You can have two different aliases for the same thing if that makes sense in different parts of your code (that's kinda the whole point of them! Relabel types to make them more readable or understandable) but that's just ways to refer to a type.
But when it comes to defining your class, it makes no sense. B and C are the same type, you're repeating yourself (and the compiler will give you a supertype appears twice error). And to implement that one type, you need one function - and only one, because if you have two identical functions then which one would get called?
So you can do this if you want:
typealias A = () -> Unit
typealias B = (something: String) -> Unit
typealias C = (somethingElse: String) -> Unit
class Test : A, B {
override fun invoke() {
println("invoke")
}
override fun invoke(something: String) {
println("invoke: $something")
}
}
fun doAThing(thing: C) {
thing("wow")
}
fun main() {
doAThing(Test())
}
doAThing takes a C, so we can pass it a B, because B is C.
I'm guessing that's not very useful to you, but that's the limitation of typealiases, and bare function types in general. If you want two separate functions with the exact same signature in the same scope, you need to be able to refer to them explicitly - and that usually means giving them different names.
How is your click-handler class going to handle your Event if you can't tell it whether it's a single or double-click? And even if you could (e.g. through something like (handlerFunction as B).invoke(event)) then which of your identical overridden functions in the class is which?
Like Mateusz says, you need to use interfaces, and then you can pass references to the functions, because you have a name for each one you can refer to. The things you're passing those functions into can define the types using typealiases if they want. And if you want a type that can handle both kinds of clicks, create another interface that implements both types.
If you want to be able to pass a single object that has multiple functions with the same signature, that's what you need. If you want to use function types instead, you'll have to pass the individual function references in - but something somewhere has to be able to distinguish between them in the first place, and that's usually where they're defined

Unexpected behavior of also/apply, cannot pass references of a instance function into also/apply

To sum up the question in a few words, here is the catch:
The also(strings::add) doesn't work, it says Type inference failed
fun test() = "Test String"
val strings = mutableListOf<String>()
// Type inference failed: inline fun <T> T.also(block: (T) -> Unit): T cannot be applied to receiver: String arguments: (<unknown>)
// None of the following functions can be called with the arguments supplied: public abstract fun add(index: Int, element: String): Unit defined in kotlin.collections.MutableList public abstract fun add(element: String): Boolean defined in kotlin.collections.MutableList
test().also(strings::add).let { /* Use the string later */ }
While doing the same with let does work in the same place:
val strings = mutableListOf<String>()
test().let(strings::add).let { println(it) } // prints true, no compile errors.
Here is the minimal reproducable code.
I want to use the string later so don't want to use let here. What should I do? If i try to use the apply the same compile error occur probably because both also and apply have same callback signature of KFunction1<T, T>. How should one pass these type of references with also/apply?
override fun add(element: E): Boolean as you can see, the function returns Boolean, but apply accepts block: T.() -> Unit, i.e. it accepts only functions that receive a single argument and return no value.

How to define functional interface with generics in Kotlin?

I'm learning Kotlin and I have some trouble with functions.
I'm trying to create something like a functional interface with a generic parameter.
In Java I would create something like this:
#FunctionalInterface
public interface Foo<T extends Bar> {
String something(T arg);
}
Then I can use this somewhere else like this (given that Person extends Bar:
Foo<Person> f = p -> p.toString();
How do you write this with Kotlin?
The first thing I tried was to use type-aliases like this:
typealias Foo<T> = (T) -> String
However, it stopped working when I added the bound to the type parameter:
typealias Foo<T: Bar> = (T) -> String // Error: Bounds are not allowed on type alias parameters
The second approach was to write an interface that extends the function type:
interface Foo<T: Bar> : (T) -> String
However, now I don't know how to instantiate a lambda function from with this. It works when I create class from it like this:
class Something: Foo<Person> {
override fun invoke(p: Person): String {
return p.toString()
}
}
val f = Something()
But this is a big overhead and I'm sure there has to be a better solution.
So how can I define a function signature that can be reused by many functions that supports generic parameters with bounds in kotlin?
Most of the time (always?) it is sufficient to define the type of the lambda in the parameter of the function that receives it.
For example:
open class Bar
class Person: Bar()
var f = { p: Person -> p.toString() }
fun <T : Bar> withFoo(block: (T) -> String) { }
fun <T : Bar> otherFoo(block: (T) -> String) { }
fun main() {
withFoo(f)
otherFoo(f)
}
The same way the Kotlin documentation states:
"since Kotlin has proper function types, automatic conversion of functions into implementations of Kotlin interfaces is unnecessary and therefore unsupported."
See https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions

How to Resolve Function Template Generics for Signal/Slot System?

I'm trying to develop a simplistic signals/slots system in Kotlin. Here's what I have so far:
open class Signal<T : Function<Unit>>() {
val callbacks = mutableListOf<T>()
open fun addCallback(slot: T) {
callbacks.add(slot)
}
open fun emit(vararg params: Any) {
for(call in callbacks) {
call(*params)
}
}
}
fun test(myarg: Int) = println(myarg)
fun main(args: Array<String>) {
val myevent = Signal<(Int) -> Unit>()
myevent.addCallback(::test)
myevent.emit(2)
}
The idea is one would create an instance of Signal along with a generic template to dictate which parameters are used for the callbacks. Callbacks can then be added to the Signal. Finally, whenever the Signal needs to be... well... "signaled", the emit method is used. This method passes all the parameters to the corresponding callbacks if necessary.
The issue is this code results in the following error:
kotlin\Signal.kt:30:4: error: expression 'call' of type 'T' cannot be invoked as a function. The function 'invoke()' is not found
The line in question is:
call(*params)
Any recommendations on how to handle things from here?
This is because Function is an empty interface (source).
The various function types that actually have invoke operators are all defined one by one here, as Function0, Function1, etc.
I don't think you'll be able to create a Signal implementation that may have callbacks with any number and any type of parameters. Could you perhaps get by with only having callbacks with a single parameter?
open class Signal<T> {
val callbacks = mutableListOf<(T) -> Unit>()
open fun addCallback(slot: (T) -> Unit) {
callbacks.add(slot)
}
open fun emit(param: T) {
for (call in callbacks) {
call(param)
}
}
}
fun test(myarg: Int) = println(myarg)
fun main(args: Array<String>) {
val myevent = Signal<Int>()
myevent.addCallback(::test)
myevent.emit(2)
}
(Note that you could replace both usages of (T) -> Unit here with Function1<T, Unit>.)

Inferring only some type parameters in Kotlin

I have a method with two type parameters, only one of which can be inferred from arguments, something like (no need to comment this cast is evil, the body is purely for the sake of example)
fun <A, B> foo(x: Any, y: A.() -> B) = (x as A).y()
// at call site
foo<String, Int>("1", { toInt() })
However, the compiler can tell B is Int if A is String. And more generally, if it knows A, B can be inferred.
Is there a way to only provide A at the call site and infer B?
Of course, the standard Scala approach works:
class <A> Foo() {
fun <B> apply(x: Any, y: A.() -> B) = ...
}
// at call site
Foo<String>().apply("1", { toInt() })
I was interested in whether Kotlin has a more direct solution.
Based on this issue/proposal, I'd say no(t yet):
Hello, I am proposing two new feature for kotlin which go hand in
hand: partial type parameter list and default type parameters :) Which
in essence allows to do something as the following:
data class Test<out T>(val value: T)
inline fun <T: Any, reified TSub: T> Test<T>.narrow(): Test<TSub>{
return if(value is TSub) Test(value as TSub) else throw ClassCastException("...")
}
fun foo() {
val i: Any = 1
Test(i).narrow<_, Int>() // the _ means let Kotlin infer the first type parameter
// Today I need to repeat the obvious:
Test(i).narrow<Any, Int>()
}
It would be even nicer, if we can define something like:
inline fun <default T: Any, reified TSub: T> Test<T>.narrow(): Test<TSub>{
return if(value is TSub) Test(value as TSub) else throw ClassCastException("...")
}
And then don't even have to write _
fun foo() {
val i: Any = 1
Test(i).narrow<Int>() //default type parameter, let Kotlin infer the first type parameter
}