I have the following simple interface
interface A {
fun move(s:Boolean): Int
}
I have the following class
class X{
fun draw (x: A): String{
return "A"
}
fun main() {
val temp = A {
s -> 100
}
val a = draw ( { x -> 100} )
}
}
However both temp and a fail to be declared. temp complains and the suggested fix is to convert to an anonymous object as follows (which defeats the whole purpose of using a SAM?)
val temp = object : A {
override fun move(s: Boolean): Int {
return 100
}
}
a complains about a type mismatch. My question is why does this simple SAM fail? The method signature is the same.
Currently Kotlin only has SAM conversion for interfaces defined in Java.
For pure Kotlin code you're supposed to use a function type such as:
typealias A = (s: Boolean) -> Int
However, the syntax you expected will be supported in Kotlin 1.4 with interface defined as fun interface.
As announced here:
What to Expect in Kotlin 1.4 and Beyond
and tracked as KT-7770
Kotlin 1.4 has support for SAM conversions for Kotlin interfaces, in addition to the Java interface SAM conversion available in previous versions. See:
https://youtrack.jetbrains.com/issue/KT-7770
https://blog.jetbrains.com/kotlin/2019/12/what-to-expect-in-kotlin-1-4-and-beyond/#language-features
With 1.4, you do need to define your interface as a "functional" interface:
fun interface A {
fun move(s:Boolean): Int
}
Related
I am a bit confused why I can do the following
val outputter1: (s: String) -> Unit = ::println
but when I do
val outputter2: Outputter = ::println
given
fun interface Outputter {
fun output(output: String)
}
I get a compilation error
None of the following functions can be called with the arguments supplied.
println() defined in kotlin.io
println(Any?) defined in kotlin.io
...
Shouldn't method references translate to SAM inteface types as well as Function types?
Apparently, SAM conversions must be explicit in assignments (despite the type declaration) using the auto-generated adapter functions:
val outputter2: Outputter = Outputter { println(it) } // OK
val outputter3: Outputter = Outputter(::println) // OK
val outputter4: Outputter = { s: String -> println(s) } // compile error
But they are inferred fine in function calls:
fun main() {
takesOutputter(::println) // OK
}
fun takesOutputter(o: Outputter) {
o.output("test")
}
For reference, checkout the doc on Kotlin SAM conversions, and this part in the Java interop section which gives more examples of SAM conversions.
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 }
Can we implement Rust like Traits and generic Traits using Kotlin Interfaces?
Also is there any way of using fn(&self) like construct in Kotlin class/interface default function implementations?
Can some examples be shown please?
Thanks
I don't know much about Rust, I'm referrring to these two videos as for what you're talking about, generic traits and &self explaination.
In kotlin you'd implement them using interfaces and classes as you've guessed.
An example of that is:
interface GenericTrait { // Same as traits
// <T:Any> just makes method to be called for non-null values, if you use <T>, you can pass null as well
fun <T: Any> method(value: T)
}
class TraitImpl : GenericTrait { // Same as structs
val isDisabled = Random.nextBoolean() // instance variable
// you can access instance parameter using the this or even not using it at all as in below
override fun <T: Any> method(value: T) {
println("Type of value is ${value::class}, and the value is $value. I am $isDisabled")
// or explicitly call ${this.isDisabled}, both are the same
}
}
fun main() {
TraitImpl().method("Hello")
TraitImpl().method(23)
TraitImpl().apply { // this: TraitImpl
method(23)
method(Unit)
}
}
Result:
Type of value is class kotlin.String, and the value is Hello. I am true
Type of value is class kotlin.Int, and the value is 23. I am true
Type of value is class kotlin.Int, and the value is 23. I am false
Type of value is class kotlin.Unit, and the value is kotlin.Unit. I am false
You can extract implementation outside if you want as an extension function just like you do in Rust.
interface GenericTrait {
val isDisabled: Boolean
}
class TraitImpl : GenericTrait {
override val isDisabled = Random.nextBoolean()
}
// define methods out of class declaration
fun <T: Any> GenericTrait.method(value: T) {
println("Type of value is ${value::class}, and the value is $value. I am $isDisabled")
}
I want to implement a functional kotlin interface (interface with a single abstract method) as a kotlin lambda. How to do that?
Kotlin interface
#FunctionalInterface
interface Foo{
fun bar(input: String): String
}
Kotlin implementation .
fun createFoo(): Foo {
return { input: String -> "Hello $input!" }
}
↑ doesn't compile ↑
It has to be implemented as object, which is ugly as hell.
fun createFoo() =
object : Foo{
override fun bar(input: String)= "Hello $input"
}
EDIT: corrected my sample interface from java to kotlin
Just add the fun keyword to your interface declaration:
fun interface Foo {
fun bar(input: String): String
}
It is the notation of functional interfaces in Kotlin (instead of #FunctionalInterface annotation in Java).
Now you can implement it like this:
Foo { input: String -> "Hello $input!" }
See more: https://kotlinlang.org/docs/fun-interfaces.html
since Kotlin v1.4
SAM conversion will be supported with version 1.4, with a new type inference algorithm.
See:
What to Expect in Kotlin 1.4 and Beyond
More powerful type inference algorithm
before Kotlin v1.4
It works if the companion object implements the invoke function taking a lambda.
Kotlin interface
interface Foo{
fun bar(input: String): String
companion object {
inline operator fun invoke(crossinline function: (String) -> String) =
object : Foo{
override fun bar(input: String) = function(input)
}
}
}
Kotlin implementation
fun createFoo()= Foo { input: String -> "Hello $input!" }
Functional/SAM interfaces defined in kotlin can't be implemented as Kotlin lambdas by design, see KT-7770.
In Kotlin an functional / SAM interface is considered as an anti-pattern, a function type should be declared instead: (String)->String. The function type can be expressed as typealias to make it look and feel like an interface: typealias Foo=(String)->String.
Note: The typealias is not visible in Java code only in Kotlin!
I want to implement a functional kotlin interface (interface with a single abstract method) as a kotlin lambda. How to do that?
Can't
It has to be implemented as object, which is ugly as hell.
Indeed.
You have two options:
1.) use typealias
typealias Foo = (String) -> String
fun createFoo(): Foo = { "Hello $it!" }
2.) depending on your API, you can define an extension function that receives the functional type (String) -> String as a crossinline argument, then invokes it inside a object: __ block. That way, you can hide the object: in a given function, and externally still be able to call it with a lambda argument. Doesn't seem applicable in this case, though.
I don't think there is a language level option to do this, but you can abstract the "ugly" code into a helper method so its easier to read where the business logic is actually needed:
Helper Method
fun Foo(body: (String) -> String) = object : Foo{
override fun bar(input: String)= body(input)
}
Business Code
fun createFoo():Foo {
return Foo {input:String -> "Hello $input!"}
}
It would be easier in your case to have the interface in Java:
fun createFoo() : Foo = Foo { "hello $it" }
But as you have a Kotlin interface instead, you are a bit out of luck here. Here is a related issue regarding this: KT-7770
A workaround to this could be (but that mainly depends on how you use that interface) to have a Kotlin interface as follows in place that is the main entry point for the Java side:
interface Foo : (String) -> String
On the Kotlin side you will not use it and the Java side should only use it to deliver functions, e.g.
// Java class
public class JFooFactory implements FooFactory {
#Override
#NotNull
public Foo createFoo() { // uses the Foo-interface from Kotlin
return input -> "hello " + input;
}
}
// Kotlin equivalent:
class KFactory : FooFactory {
override fun createFoo() : (String) -> String = {
"hello $it"
}
}
where the corresponding FooFactory-interface could look like:
interface FooFactory {
fun createFoo() : (String) -> String
}
Usage could look like:
listOf(KFooFactory(), JFooFactory())
.map {
it.createFoo()
}
.forEach { func : (String) -> String -> // i.e. func is of (sub)type (String) -> String
func("demo") // calling it to deliver "hello demo" twice
}
Alternatively, to have also that Foo-feeling for Kotlin you can do it as follows:
typealias Foo = (String) -> String
interface JFoo : Foo
// or if you put the interface in its own package you could also use:
interface Foo : someother.package.Foo
then the Java code stays the same as above, either with JFoo or with Foo pointing to that other package; the typealias is not visible from Java. The Kotlin side would change to the following:
class KFactory : FooFactory {
override fun createFoo() : Foo = {
"hello $it"
}
}
The Factory-interface could also be replaced:
interface FooFactory {
fun createFoo() : Foo
}
Under the hood however everything stays the same. We have/use (String) -> String in Kotlin and Foo-functional-interface in Java.
To use Kotlin lambda to Java SAM interface conversion anywhere you want, simply specify the name of the interface before the lambda.
fun createFoo(): Foo {
return Foo { input:String -> "Hello $input!" }
}
It doesn't even need to be that long.
fun createFoo(): Foo {
return Foo { "Hello $it!" }
}
As long as the interface has a single method and is declared in Java, that's all you need to do.
I have a Java example where a method is implemented as
#Override
public Function<ISeq<Item>, Double> fitness() {
return items -> {
final Item sum = items.stream().collect(Item.toSum());
return sum._size <= _knapsackSize ? sum._value : 0;
};
}
IntelliJ's automatic translation of it to Kotlin is
override fun fitness(): Function<ISeq<Item>, Double> {
return { items:ISeq<Item> ->
val sum = items.stream().collect(Item.toSum())
if (sum.size <= _knapsackSize) sum.value else 0.0
}
}
(I made the type of items explicit and changed return to 0.0)
Still I see that there are compatibility problems with Java's Function and Kotlin native lambdas, but I'm not that the most familiar with these. Error is:
Question is: is it possible to override in Kotlin the external Java library's fitness() method on this example and if so how ?
Problem:
You are returning a (Kotlin) lambda ISeq<Knapsack.Item> -> Double. But this is not what you want. You want to return a Java Function<ISeq<Knapsack.Item>, Double>.
Solution:
You can use a SAM Conversion to create a Function.
Just like Java 8, Kotlin supports SAM conversions. This means that
Kotlin function literals can be automatically converted into
implementations of Java interfaces with a single non-default method,
as long as the parameter types of the interface method match the
parameter types of the Kotlin function.
I created a minimal example to demonstrate that. Consider you have a Java class like this:
public class Foo {
public Function<String, Integer> getFunction() {
return item -> Integer.valueOf(item);
}
}
If you want to override getFunction in Kotlin you would do it like this:
class Bar: Foo() {
override fun getFunction(): Function<String, Int> {
return Function {
it.toInt()
}
}
}
When returning lambda as Java's functional interface, you have to use explicit SAM constructor:
override fun fitness(): Function<ISeq<Item>, Double> {
return Function { items:ISeq<Item> ->
val sum = items.stream().collect(Item.toSum())
if (sum.size <= _knapsackSize) sum.value else 0.0
}
}
Also don't forget to import java.util.function.Function since Kotlin has its own class of that name