extension property — un mécanisme Kotlin qui permet d'ajouter de nouvelles propriétés à des classes existantes sans héritage et sans modifier le code source. Contrairement aux extension functions, les extension properties ne peuvent pas stocker d'état — elles sont déclarées uniquement avec un getter et, optionnellement, un setter, car elles n'ont pas de backing field. Selon Kotlin Documentation, 2025, les extension properties sont compilées en méthodes statiques getter et setter avec le receiver comme premier paramètre.
Points clés
Une extension property est une construction syntaxique en Kotlin qui ajoute une propriété à un type existant sans modifier sa déclaration. La propriété est déclarée avec un receiver type et doit contenir un getter. La différence clé avec les propriétés normales est l'absence de backing field : une extension property ne peut pas stocker de données, seulement les calculer à partir de l'objet receiver.
Selon l'enquête Kotlin Foundation (2024), les extension properties sont moins populaires que les extension functions — environ 45 % des développeurs les utilisent régulièrement. Cela est dû à la limitation de ne pas avoir d'état, ce qui réduit le champ d'application. Néanmoins, pour les propriétés calculées logiquement liées à un type, les extension properties sont l'option la plus concise.
Les extension properties sont compilées en une paire de méthodes statiques getter et setter. Au niveau du bytecode, il n'y a pas de différence entre l'appel d'une extension property et l'appel d'une extension function — les deux deviennent des méthodes statiques avec un paramètre receiver. Selon JetBrains (Kotlin Docs, 2025), il n'y a aucune surcharge.
Utilisez les extension properties pour les courtes valeurs calculées qui doivent ressembler à des propriétés plutôt qu'à des appels de méthode — cela améliore la lisibilité du code et respecte le principe d'accès uniforme.
Pour déclarer une extension property, utilisez une syntaxe similaire à une propriété normale, mais avec le préfixe du receiver type. val déclare une extension property en lecture seule avec un getter obligatoire, var déclare une mutable avec un getter et un setter optionnel.
// Extension property en lecture seule
val String.isEmail: Boolean
get() = this.contains("@") && this.contains(".")
// Appel
val valid = "test@test.com".isEmail
Remarque : une extension property est appelée sans parenthèses — str.isEmail, pas str.isEmail(). C'est la différence clé entre une extension property et une extension function : une propriété ressemble à un champ, bien qu'elle soit en réalité calculée via un getter.
Les extension properties peuvent être génériques — le receiver peut utiliser des paramètres de type générique. Cela permet de créer des propriétés universelles qui fonctionnent avec n'importe quel type de collection.
val List<T>.secondOrNull: T?
get() = if (size >= 2) this[1] else null
val items = listOf("a", "b", "c")
val second = items.secondOrNull // "b"
La propriété secondOrNull fonctionne pour tout type T, retournant le deuxième élément de la liste ou null s'il y a moins de deux éléments. C'est un exemple typique où une extension property est plus appropriée qu'une fonction — son accès ressemble à la lecture d'un champ.
Une extension property ne peut pas avoir de backing field car elle n'est pas ajoutée aux métadonnées de la classe — elle existe uniquement comme une paire de fonctions statiques getter/setter. Backing field (le mot-clé field en Kotlin) est un champ interne de la classe qui stocke la valeur de la propriété. Une extension property n'a pas accès à la structure interne de la classe.
// ❌ ERREUR : une extension property ne peut pas avoir de backing field
var String.cachedValue: String
get() = "computed"
set(value) {
field = value // le champ n'est pas accessible !
}
// ✅ CORRECT : utilisez un stockage externe
val cache = MutableMap<String, String>()
var String.cachedValue: String
get() = cache[this] ?: ""
set(value) { cache[this] = value }
Une Map externe dans l'exemple résout le problème de stockage mais en crée un autre — une fuite mémoire. Les valeurs obtenues via une extension property vivent dans la Map pour toujours si elles ne sont pas nettoyées. Cette limitation rend les extension properties inadaptées au caching ou au stockage de données temporaires.
Pour le caching, il est recommandé d'utiliser une WeakHashMap ou des mécanismes avec nettoyage automatique. JetBrains recommande d'éviter l'utilisation de var extension properties avec stockage externe dans du code de production sans une gestion minutieuse du cycle de vie.
Le choix entre une extension property et une extension function dépend de la sémantique : une propriété décrit une caractéristique d'un objet, tandis qu'une fonction décrit une action. Le principe d'accès uniforme stipule : le client ne doit pas savoir si une valeur est calculée ou stockée. Si la valeur peut être représentée comme une caractéristique (longueur, taille, statut) — utilisez une propriété.
| Critère | Extension property | Extension function |
|---|---|---|
| Appel | Sans parenthèses : obj.property | Avec parenthèses : obj.function() |
| Sémantique | Caractéristique, attribut | Action, opération |
| Backing field | Non supporté | Non applicable |
| Paramètres | Uniquement getter/setter | N'importe quels paramètres |
| Performance | Identique (méthode statique) | Identique (méthode statique) |
| Exemple | text.length | text.isEmail() |
La règle est simple : si l'opération accepte des paramètres — utilisez une extension function. S'il s'agit d'une simple valeur calculée sans paramètres — utilisez une extension property. Selon le guide Android Architecture Guide (Google, 2025), la préférence doit être donnée aux extension properties pour l'accès aux données et aux extension functions pour les opérations avec effets secondaires.
Une extension property avec le mot-clé var supporte un setter, mais sans la capacité de stocker une valeur — le setter effectue généralement un effet secondaire ou sauvegarde des données dans un stockage externe. La syntaxe est similaire aux propriétés mutables de classe.
// Extension property mutable avec setter
var StringBuilder.lastChar: Char
get() = this[length - 1]
set(value) {
this.setCharAt(length - 1, value)
}
val sb = StringBuilder("Kotlin")
println(sb.lastChar) // n
sb.lastChar = ' !'
println(sb) // Kotli !
La propriété lastChar est un exemple classique de la documentation Kotlin. Le getter retourne le dernier caractère de StringBuilder, le setter le remplace par une nouvelle valeur. Remarque : l'état est stocké dans le StringBuilder lui-même (via setCharAt), pas dans un champ séparé — c'est une utilisation correcte d'une extension property.
Dans les projets réels, les extension properties sont le plus souvent utilisées pour simplifier l'accès aux données de collections, calculer les tailles ou statuts des éléments d'interface utilisateur, et créer une API pratique au-dessus de classes existantes. La bibliothèque standard Kotlin utilise activement ce mécanisme : size, indices, lastIndex pour les collections sont des extension properties.
// Extension properties pour collections
val List<Int>.sumFast: Int
get() = fold(0) { acc, i -> acc + i }
val String.half: String
get() = this.substring(0, length / 2)
// Extension property pour Android View
val View.isVisible: Boolean
get() = visibility == View.VISIBLE
// Vérification nulle via receiver sécurisé
val String?.isNullOrBlank: Boolean
get() = this == null || this.isBlank()
L'extension property isVisible pour View est un exemple que tout développeur Android devrait connaître. Au lieu de view.visibility == View.VISIBLE, vous pouvez écrire view.isVisible. Ce n'est pas seulement plus court, mais ça se lit aussi comme un langage naturel : « si la vue est visible ». Malgré leur simplicité, ces propriétés améliorent considérablement la lisibilité du code.
Questions fréquentes
Non, les extension properties ne peuvent pas être déclarées pour un companion object ou une déclaration object. Le mécanisme d'extension s'applique uniquement aux classes, interfaces et types nullables. Pour object, utilisez des fonctions normales de niveau supérieur.
Une propriété inline (avec le modificateur inline) est un mécanisme Kotlin pour appeler un getter/setter sans créer d'objet propriété. Une extension property est toujours compilée en une méthode statique, tandis qu'une propriété inline est compilée en un appel sans wrapper. Elles résolvent des problèmes différents : une extension property ajoute une propriété à un type existant, tandis qu'inline optimise les appels à ses propres propriétés.
Oui, une extension property peut avoir des annotations, mais uniquement au niveau de la déclaration. Contrairement aux propriétés de classe normales, vous ne pouvez pas annoter séparément le getter ou le setter d'une extension property. Exemple : @JvmName("getIsValid") val String.isValid get() = true.
Non, les extension properties ne peuvent pas être déclarées avec un companion object comme receiver. C'est une limitation du langage — une extension property fonctionne uniquement avec des instances de type, tandis qu'un companion object est un contexte statique. Utilisez des fonctions d'extension de niveau supérieur ou des constantes.
Minimalement. Chaque extension property ajoute une méthode getter statique (et optionnellement un setter) au bytecode compilé. Pour comparaison, créer une classe wrapper avec la même propriété ajoute une classe entière. Les extension properties sont une approche plus légère pour étendre les fonctionnalités.
Résumé
Nous développerons une application mobile clé en main
IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.
Lisez aussi