Kotlin tiene soporte incorporado para propiedades delegadas (delegated properties). El mecanismo by permite delegar el getter/setter de cualquier propiedad a un objeto especializado — el delegado. Los delegados más conocidos son: lazy, observable, vetoable y los personalizados.
Ventajas:
Ejemplo de delegado personalizado:
class UpperCaseDelegate { private var value: String = "" operator fun getValue(thisRef: Any?, property: KProperty<*>): String = value operator fun setValue(thisRef: Any?, property: KProperty<*>, newValue: String) { value = newValue.uppercase() } } class Person { var name: String by UpperCaseDelegate() }
Limitaciones:
¿Se puede usar un delegado que requiere acceso al contexto (por ejemplo, Android Context) en propiedades de objetos compañeras o de nivel superior?
A menudo se responde incorrectamente que "sí, siempre, ¿por qué no?"
Respuesta correcta: No, porque los objetos compañeros y los objetos de nivel superior se inicializan antes de que se inicialicen las instancias de la clase o de la aplicación, lo que puede llevar a errores relacionados con el acceso a un contexto no inicializado. Los delegados que requieren acceso a instancias solo deben usarse en propiedades de clase.
Historia
Delegación de inicialización perezosa en Android-ViewModel: Un programador movió un delegado heavy-lazy a un objeto compañero. En ciertas situaciones (después de actualizar el SDK), la aplicación comenzó a fallar en la inicialización: el contexto aún no estaba disponible, pero el delegado ya había ejecutado su "init".
Historia
Serialización incorrecta con delegados: Se usó un delegado personalizado para almacenar datos; sin embargo, contenía referencias no serializables al contexto. Al intentar serializar, se produjeron errores y pérdida de datos.
Historia
Delegado observable con error de callback: Un desarrollador utilizó Delegates.observable para controlar el estado; dentro de la lambda se asignó un nuevo valor, lo que llevó a un bucle infinito y StackOverflowError en tiempo de ejecución.