Extension functions/estensioni — sono un meccanismo che consente di aggiungere nuove funzioni a classi esistenti senza la necessità di ereditare o modificare la classe stessa.
Ad esempio, per la classe String, aggiungiamo una funzione che inverte la stringa:
fun String.reverse(): String { return this.reversed() } println("abc".reverse()) // "cba"
Le estensioni in realtà non modificano la classe, ma sono semplicemente zucchero sintattico: vengono compilate come metodi statici che prendono l'istanza dell'oggetto come primo parametro.
Vantaggi: concisione, leggibilità, estensibilità del codice. Si adattano bene a funzioni di utilità per collezioni, stringhe, ecc.
Insidie:
È possibile utilizzare le extension functions per aggiungere una nuova variabile (property) che memorizza lo stato a una classe?
Risposta: No. L'extension property è sempre una proprietà calcolata (getter/setter), non un campo. Non possono memorizzare stato — solo calcolarlo al volo.
val String.secondChar: Char get() = this[1] // Solo calcolo, non memorizzazione!
Storia
In un progetto di verifica dei dati, uno sviluppatore ha aggiunto un'extension property a una classe modello come se memorizzasse un valore, ma in seguito ha notato che il valore veniva sempre calcolato e non memorizzato, il che ha causato un comportamento errato della logica a seguito di chiamate ripetute.
Storia
In una grande applicazione, le estensioni sono state denominate allo stesso modo dei metodi della classe, il che ha portato a confusione: i metodi della classe avevano sempre la priorità, mentre le estensioni non venivano chiamate — un giorno speso per il debugging di codice "invisibile".
Storia
In una delle librerie, le estensioni erano usate per i campi privati della classe, ma in seguito si è scoperto che non avevano diritti di accesso ai membri privati, il che ha comportato la necessità di rifattorizzare l'architettura dei modelli.