Les fonctions d'extension — c'est un mécanisme qui permet d'ajouter de nouvelles fonctions à des classes existantes sans avoir besoin d'héritage ou de modifier la classe elle-même.
Par exemple, pour la classe String, ajoutons une fonction qui renverse une chaîne :
fun String.reverse(): String { return this.reversed() } println("abc".reverse()) // "cba"
Les extensions ne modifient en réalité pas la classe, mais sont simplement un sucre syntaxique : elles sont compilées comme des méthodes statiques prenant une instance d'objet comme premier paramètre.
Avantages : concision, lisibilité, extensibilité du code. Conviennent bien aux fonctions utilitaires pour les collections, les chaînes, etc.
Pièges :
Peut-on utiliser les fonctions d'extension pour ajouter une nouvelle variable (property) qui stocke l'état à une classe ?
Réponse : Non. La propriété d'extension est toujours une propriété calculée (getter/setter), pas un champ. Elles ne peuvent pas stocker l'état — seulement calculer à la volée.
val String.secondChar: Char get() = this[1] // Seulement un calcul, pas un stockage !
Histoire
Dans un projet de vérification de données, un développeur a ajouté une propriété d'extension à une classe modèle comme si elle stockait une valeur, mais a remarqué plus tard que la valeur était toujours calculée, pas mémorisée, ce qui a entraîné un comportement incorrect de la logique lors d'appels répétés.
Histoire
Dans une grande application, les extensions ont été nommées de la même manière que les méthodes de la classe, ce qui a conduit à de la confusion : les méthodes de classe avaient toujours la priorité, et les extensions n'étaient pas appelées — une journée a été perdue à déboguer un code "invisible".
Histoire
Dans l'une des bibliothèques, des extensions étaient utilisées pour des champs privés de la classe, mais il s'est avéré qu'elles n'avaient pas accès au private, ce qui a nécessité de refactoriser l'architecture des modèles.