extension property — een Kotlin-mechanisme waarmee nieuwe eigenschappen aan bestaande klassen kunnen worden toegevoegd zonder overerving en zonder wijziging van de broncode. In tegenstelling tot extension functions kunnen eigenschap-uitbreidingen geen status opslaan — ze worden alleen gedeclareerd met een getter en optioneel een setter, omdat ze geen backing field hebben. Volgens Kotlin Documentation, 2025 worden extension properties gecompileerd naar statische getter- en setter-methoden met receiver als eerste parameter.
Belangrijkste punten
extension property — is een syntactische constructie in Kotlin die een eigenschap toevoegt aan een bestaand type zonder de declaratie ervan te wijzigen. De eigenschap wordt gedeclareerd met specificatie van het receiver-type en bevat verplicht een getter. Het belangrijkste verschil met gewone eigenschappen — het ontbreken van een backing field: extension property kan geen gegevens opslaan, maar berekent ze alleen op basis van het receiver-object.
Volgens Kotlin Foundation Survey (2024) zijn extension properties minder populair dan extension functions — ongeveer 45% van de ontwikkelaars gebruikt ze regelmatig. Dit komt door de beperking van het ontbreken van status, wat het toepassingsgebied beperkt. Desalniettemin zijn extension properties voor berekende eigenschappen die logisch aan het type zijn gekoppeld, de meest beknopte optie.
Extension properties worden gecompileerd naar een paar statische getter- en setter-methoden. Op bytecode-niveau is er geen verschil tussen het aanroepen van een extension property en een extension function — beide worden statische methoden met een receiver-parameter. Volgens gegevens van JetBrains (Kotlin Docs, 2025) is er helemaal geen overhead.
Gebruik extension properties voor korte berekende waarden die eruit moeten zien als eigenschappen, niet als methodaanroepen — dit verbetert de leesbaarheid van de code en volgt het uniforme toegangsprincipe.
Voor het declareren van een extension property wordt een syntax gebruikt die lijkt op een gewone eigenschap, maar met een prefix van het receiver-type. val declareert een read-only extension property met een verplichte getter, var — mutable met een getter en optionele setter.
// Alleen-lezen extension property
val String.isEmail: Boolean
get() = this.contains("@") && this.contains(".")
// Aanroep
val valid = "test@test.com".isEmail
Let op: extension property wordt zonder haakjes aangeroepen — str.isEmail, niet str.isEmail(). Dit is het belangrijkste verschil tussen extension property en extension function: property ziet eruit als een veld, hoewel het in werkelijkheid via de getter wordt berekend.
Extension properties kunnen generiek zijn — receiver kan generic-parameters gebruiken. Dit maakt het mogelijk om universele eigenschappen te maken die met elk type verzameling werken.
val List<T>.secondOrNull: T?
get() = if (size >= 2) this[1] else null
val items = listOf("a", "b", "c")
val second = items.secondOrNull // "b"
De eigenschap secondOrNull werkt voor elk type T en retourneert het tweede element van de lijst of null als er minder dan twee elementen zijn. Dit is een typisch voorbeeld waar extension property geschikter is dan een functie — de toegang ziet eruit als het lezen van een veld.
Een extension property kan geen backing field hebben omdat het niet aan de metadata van de klasse wordt toegevoegd — het bestaat alleen als een paar statische getter/setter-functies. Backing field (het sleutelwoord field in Kotlin) — is het interne veld van de klasse dat de waarde van de eigenschap opslaat. Extension property heeft geen toegang tot de interne structuur van de klasse.
// ❌ FOUT: extension property kan geen backing field hebben
var String.cachedValue: String
get() = "computed"
set(value) {
field = value // veld is niet toegankelijk!
}
// ✅ CORRECT: gebruik externe opslag
val cache = MutableMap<String, String>()
var String.cachedValue: String
get() = cache[this] ?: ""
set(value) { cache[this] = value }
De externe Map in het voorbeeld lost het opslagprobleem op, maar creëert een ander — geheugenlek. Waarden die via extension property worden verkregen, leven voor altijd in de Map als ze niet worden opgeschoond. Deze beperking maakt extension properties ongeschikt voor caching of tijdelijke gegevensopslag.
Voor caching wordt het gebruik van WeakHashMap of mechanismen met automatische opschoning aanbevolen. JetBrains raadt aan om het gebruik van var extension properties met externe opslag in productiecode zonder zorgvuldig levenscyclusbeheer te vermijden.
De keuze tussen extension property en extension function hangt af van de semantiek: een eigenschap beschrijft een kenmerk van een object, een functie beschrijft een actie. Het uniforme toegangsprincipe (Uniform Access Principle) stelt: de client moet niet weten of de waarde wordt berekend of opgeslagen. Als de waarde als een kenmerk kan worden weergegeven (lengte, grootte, status) — gebruik dan property.
| Criterium | Extension property | Extension function |
|---|---|---|
| Aanroep | Zonder haakjes: obj.property | Met haakjes: obj.function() |
| Semantiek | Kenmerk, attribuut | Actie, operatie |
| Backing field | Niet ondersteund | Niet van toepassing |
| Parameters | Alleen getter/setter | Alle parameters |
| Prestaties | Hetzelfde (statische methode) | Hetzelfde (statische methode) |
| Voorbeeld | text.length | text.isEmail() |
De regel is eenvoudig: als de operatie parameters accepteert — gebruik dan extension function. Als het een eenvoudige berekende waarde zonder parameters is — extension property. Volgens Android Architecture Guide (Google, 2025) verdienen extension properties de voorkeur voor gegevenstoegang en extension functions voor bewerkingen met bijwerkingen.
Extension property met het sleutelwoord var ondersteunt een setter, maar zonder de mogelijkheid om de waarde op te slaan — de setter voert meestal een bijwerking uit of slaat gegevens op in een externe opslag. De syntax is analoog aan mutable eigenschappen van klassen.
// Mutable extension property met 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!
De eigenschap lastChar — een klassiek voorbeeld uit de Kotlin-documentatie. De getter retourneert het laatste teken van StringBuilder, de setter vervangt het door een nieuwe waarde. Let op: de status wordt opgeslagen in de StringBuilder zelf (via setCharAt), niet in een apart veld — dit is correct gebruik van extension property.
In echte projecten worden extension properties het vaakst gebruikt voor het vereenvoudigen van toegang tot verzamelingsgegevens, het berekenen van afmetingen of statussen van UI-elementen en het creëren van een handige API bovenop bestaande klassen. De Kotlin-standaardbibliotheek maakt actief gebruik van dit mechanisme: size, indices, lastIndex voor verzamelingen — dit zijn extension properties.
// Extension properties voor verzamelingen
val List<Int>.sumFast: Int
get() = fold(0) { acc, i -> acc + i }
val String.half: String
get() = this.substring(0, length / 2)
// Extension property voor Android View
val View.isVisible: Boolean
get() = visibility == View.VISIBLE
// Null-controle via veilige receiver
val String?.isNullOrBlank: Boolean
get() = this == null || this.isBlank()
Extension property isVisible voor View — een voorbeeld dat elke Android-ontwikkelaar zou moeten kennen. In plaats van view.visibility == View.VISIBLE kun je view.isVisible schrijven. Het is niet alleen korter, maar leest als natuurlijke taal: “als de weergave zichtbaar is”. Ondanks de eenvoud verbeteren dergelijke eigenschappen de leesbaarheid van de code aanzienlijk.
Veelgestelde vragen
Nee, extension properties kunnen niet worden gedeclareerd voor companion object of object declaration. Het extension-mechanisme is alleen van toepassing op klassen, interfaces en nullable types. Gebruik voor object gewone functies op het hoogste niveau.
Een inline-eigenschap (met de modifier inline) — een Kotlin-mechanisme voor het aanroepen van getter/setter zonder het maken van een eigenschapsobject. Extension property wordt altijd gecompileerd naar een statische methode, terwijl een inline-eigenschap wordt gecompileerd naar een aanroep zonder wrapper. Ze lossen verschillende taken op: extension property voegt een eigenschap toe aan een bestaand type, inline optimaliseert aanroepen van eigen eigenschappen.
Ja, extension property kan annotaties bevatten, maar alleen op declaratieniveau. De getter of setter van een extension property kunnen niet afzonderlijk worden geannoteerd — in tegenstelling tot gewone klassen-eigenschappen. Voorbeeld: @JvmName(“getIsValid”) val String.isValid get() = true.
Nee, extension properties kunnen niet worden gedeclareerd met companion object als receiver. Dit is een taalbeperking — extension property werkt alleen met instanties van types, en companion object is een statische context. Gebruik extension functions op het hoogste niveau of constanten.
Minimaal. Elke extension property voegt één statische getter-methode (en optioneel setter) toe aan de gecompileerde bytecode. Ter vergelijking: het maken van een wrapper-klasse met dezelfde eigenschap voegt een hele klasse toe. Extension properties — een lichtere benadering voor het uitbreiden van functionaliteit.
Samenvatting
We ontwikkelen een mobiele applicatie turnkey
IT Sectr creëert sinds 2017 iOS- en Android-applicaties voor startups en bedrijven. We adviseren u en stellen de beste oplossing voor.
Lees ook