Definición de la function: fun vs val

Tengo curiosidad sobre cuál es la forma sugerida de definir las funciones de miembros en Kotlin. Considere estas dos funciones miembro:

class A { fun f(x: Int) = 42 val g = fun(x: Int) = 42 } 

Estos parecen lograr lo mismo, pero encontré diferencias sutiles.

La definición basada en val , por ejemplo, parece ser más flexible en algunos escenarios. Es decir, no pude encontrar una manera directa de componer f con otras funciones, pero pude con g . Para jugar con estas definiciones, utilicé la biblioteca funKTionale . Descubrí que esto no comstack:

 val z = g andThen A::f // f is a member function 

Pero si f se definiera como un val apunte a la misma function, se comstackría muy bien. Para descubrir qué estaba pasando le pedí a IntelliJ que definiera explícitamente el tipo de ::f g para mí, y me da esto:

 val fref: KFunction1<Int, Int> = ::f val gref: (Int) -> Int = g 

Entonces uno es del tipo KFunction1<Int, Int> , el otro es del tipo (Int) -> Int . Es fácil ver que ambos representan funciones de tipo Int -> Int .

¿Cuál es la diferencia entre estos dos types y en qué casos importa? Noté que para las funciones de nivel superior, puedo componerlas bien usando cualquiera de las definiciones, pero para hacer la compilation de composition antes mencionada, tuve que escribirla así:

 val z = g andThen A::f.partially1(this) 

es decir, tuve que aplicarlo parcialmente a this primero.

Como no tengo que pasar por esta molestia cuando uso val para las funciones, ¿hay alguna razón por la que alguna vez deba definir las funciones de los miembros que no son de la Unidad utilizando la fun ? ¿Hay alguna diferencia en el performance o la semántica que me falta?

Kotlin tiene que ver con la interoperabilidad de Java y definir una function como val producirá un resultado completamente diferente en términos de interoperabilidad. La siguiente class de Kotlin:

 class A { fun f(x: Int) = 42 val g = fun(x: Int) = 42 } 

es efectivamente equivalente a:

 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; } } 

Como puede ver, las principales diferencias son:

  1. fun f es solo un método habitual, mientras que val g en realidad es una function de order superior que devuelve otra function
  2. val g implica la creación de una nueva class que no es buena si estás apuntando a Android
  3. val g requiere un boxeo y unboxing innecesarios
  4. val g no se puede invocar fácilmente desde java: A().g(42) en Kotlin vs new A().getG().invoke(42) en Java

ACTUALIZAR:

En cuanto a la syntax A::f . El comstackdor generará una class adicional Function2<A, Integer, Integer> para cada ocurrencia A::f , por lo que el siguiente código da como resultado dos classs extra con 7 methods cada una:

 val first = A::f val second = A::f 

El comstackdor de Kotlin no es lo suficientemente inteligente en este momento para optimizar este tipo de cosas. Puede votar por el problema aquí https://youtrack.jetbrains.com/issue/KT-9831 . En caso de que le interese, así es como se ve cada class en el bytecode: https://gist.github.com/nsk-mironov/fc13f2075bfa05d8a3c3

Aquí hay un código que muestra cómo f y g son diferentes cuando se trata de uso:

 fun main(args: Array<String>) { val a = A() exe(ag) // OK //exe(af) // does not compile exe { af(it) } // OK } fun exe(p: (Int) -> Int) { println(p(0)) } 

Puedes ver que g es un object que puede usarse como un lambda, pero f no puede. Para usar f de manera similar, debes envolverlo en una lambda.

  • Asynchronization de reference no resuelta en Kotlin
  • Problema recursivo con toString en Kotlin
  • Función de llamada de la class Kotlin del método de la class Java
  • ¿Por qué este ChildEventListener no está leyendo datos del nodo firebase?
  • ¿Cómo puedo definir una vista de text fuera de la class de actividad?
  • El operador "si" de Elvis en Kotlin como argumento pnetworkingeterminado de la function
  • Elementos seleccionados en el menu
  • Ninguno de los siguientes candidatos es responsable debido a la falta de coincidencia del tipo de receptor
  • ¿Usando rasgos con classs de datos en Kotlin?
  • ¿Cómo puedo anular un método de Java y cambiar la capacidad de anulación de un parámetro?
  • Cómo vincular el button con el website en el estudio de Android usando kotlin