Hi, why is a SAM implementation producing differen...
# compiler
h
Hi, why is a SAM implementation producing different compiler outputs depending on if object or lambda style notation are being used?
Copy code
fun interface SmthgSAMGeneric<T> {
    fun foo(): (T, T) -> String
}

 val samAsObject = object : SmthgSAMGeneric<String> {
        override fun foo(): (String, String) -> String {
            return { s: String, s2: String -> "42" }
        }
    }

val inlineSam = SmthgSAMGeneric<String> {
    { s: String, s2: String -> "42" }
}
See also https://github.com/EsotericSoftware/kryo/issues/867
b
cc @dmitry.petrov
d
Sorry for a delay.
Copy code
val samAsObject = object : SmthgSAMGeneric<String> {
        override fun foo(): (String, String) -> String {
            return { s: String, s2: String -> "42" }
        }
    }
is just an anonymous class implementing SAM interface.
Copy code
val inlineSam = SmthgSAMGeneric<String> {
    { s: String, s2: String -> "42" }
}
is a SAM conversion on lambda, which is generated as invokedynamic with java.lang.invoke.LambdaMetafactory. Corresponding class has non-stable class name, is not accessible by name via reflection, and is not serializable unless corresponding SAM interface extends Serializable (there's special magic in LambdaMetafactory for serialization support). But, well, if you work with kryo, you probably know that all already.
h
Thanks for the clarification @dmitry.petrov. I'm very new to kryo and serialization, so your explanation helps a lot. Do you know if LambdaMetafactory could be used in conjunction with kryo to serialize SAM conversions?
d
LambdaMetafactory is not used "directly" in this case - it provides a bootstrap method used to create a SAM wrapper class at run time (instead of compile time). Unfortunately, simply creating a Serializable SAM wrapper with LambdaMetafactory is not enough; enclosing class should provide a special method to deserialize it. All that is generated by Kotlin compiler in case of SAM conversion to a Serializable SAM interface - that is, just make it extend Serializable:
Copy code
fun interface SmthgSAMGeneric<T> : Serializable {
    fun foo(): (T, T) -> String
}
Then SAM conversions to
SmthSAMGeneric
will become serializable. Kryo knows about related LambdaMetafactory "magic" and can handle such serialized SAM wrappers.
h
Thanks for working out the differences between the 2 concepts @dmitry.petrov