9

I have a Java Class function as below

public void setPositiveButton(int resId, DialogInterface.OnClickListener listener) 

I also have the same Kotlin Class function as below

fun setPositiveButton(resId: Int, listener: DialogInterface.OnClickListener)

When I call them from a Kotlin code

    javaClassObj.setPositiveButton(R.string.some_string,
            DialogInterface.OnClickListener { _, _ -> someFunc()})

    kotlinClassObj.setPositiveButton(R.string.some_string,
            DialogInterface.OnClickListener { _, _ -> someFunc()})

The Java Class function call could be reduced, but not the Kotlin Class function

    javaClassObj.setPositiveButton(R.string.some_string,
            { _, _ -> someFunc()})

    kotlinClassObj.setPositiveButton(R.string.some_string,
            DialogInterface.OnClickListener { _, _ -> someFunc()})

Why can't the Kotlin function call reduce the redundant SAM-Constructor as per enabled for Java?

Elye
  • 53,639
  • 54
  • 212
  • 474
  • I'm using Kotlin version 1.1.4-3 on Android.Studio – Elye Sep 05 '17 at 09:30
  • Possible duplicate of [Why do Lambda expressions behave differently for Kotlin and Java classes?](https://stackoverflow.com/questions/44324821/why-do-lambda-expressions-behave-differently-for-kotlin-and-java-classes) – BakaWaii Sep 05 '17 at 09:33

2 Answers2

14

Why would you use SAM in kotlin? while it has native support for functions.

The SAM convention is used in java8 as a workaround not having native function support.

from kotlin doc#sam-conversions:

Note that SAM conversions only work for interfaces, not for abstract classes, even if those also have just a single abstract method.

Also, note that this feature works only for Java interop; since Kotlin has proper function types, automatic conversion of functions into implementations of Kotlin interfaces is unnecessary and therefore unsupported.

you should then declare a function directly.

fun setPositiveButton(resId: Int, listener: (DialogInterface, Int) -> Unit) {
    listener.invoke(
            //DialogInterface, Int
    )
}

and then it can be used

setPositiveButton(1, { _, _ -> doStuff() })

In kotlin 1.4 you can use SAM conversions for Kotlin classes.

fun interface Listener {
    fun listen()
}

fun addListener(listener: Listener) = a.listen()

fun main() {
    addListener {
        println("Hello!")
    }
}
humazed
  • 74,687
  • 32
  • 99
  • 138
  • 3
    The (terrible) Android Developers Guide tells people to use SAM. Thanks for explaining why it's bad. – Prime624 Jan 21 '19 at 23:49
  • 2
    My guess this is from the days when Java was the only language, and the engineer responsible for converting docs to support kotlin didn't bother to change the code to use the kotlin way and just convert the java code to kotlin. or maybe he creates a script to convert it to automate his job :D – humazed Jan 23 '19 at 11:26
  • Why would you use SAM in kotlin? while it has native support for functions. Because its easier to document a functional interface, its purpose and its function compared to using kotlin's function syntax on the fly. For example, accepting Compartor interface is much more readable than, taking (T1, T2) -> boolean, because comparator interface's compare method is well documented in its own file. – Manish Chandra Joshi Feb 24 '22 at 17:07
3

Extending @humazed answer as compiler complains that

lambda argument should be moved out of parenthesis

setPositiveButton("ok"){_,_ -> doSomething()}
asim
  • 533
  • 6
  • 17