Achtergrond:
Shadowing is het fenomeen waarbij een variabele met dezelfde naam wordt gedeclareerd in een interne zichtbaarheid, waardoor de variabele uit de externe zichtbaarheid wordt overschreven (verduisterd). In eerdere versies van Swift was de compiler niet strikt met betrekking tot shadowing, maar met de complexiteit van het taalsysteem werd het essentieel om dergelijke situaties expliciet te identificeren om bugs te voorkomen.
Probleem:
Shadowing bemoeilijkt het onderhoud van de code en veroorzaakt moeilijk zichtbare fouten — een per ongeluk gedeclareerde variabele met dezelfde naam kan ertoe leiden dat de verwijzing niet naar de verwachte variabele gaat. Dit is vooral kritisch in gevallen waar variabelen via een referentie worden doorgegeven, en binnen lussen of closures — vaak verschijnen fouten pas tijdens runtime.
Oplossing:
Swift staat shadowing van variabelen toe, maar het wordt aanbevolen om belangrijke variabelen/eigenschappen te vermijden te verduisteren, verschillende namen te gebruiken of expliciete self/this-referenties te gebruiken. Vooral in initializers van struct/class wordt aangeraden om self te gebruiken om het lid en de parameter te onderscheiden:
Voorbeeldcode:
struct User { let name: String init(name: String) { self.name = name // self zorgt voor expliciete toewijzing } }
Belangrijke punten:
Wat gebeurt er bij shadowing in lussen en closures?
Als je een variabele declareert binnen een closure met dezelfde naam als in de externe context, zal shadowing de externe variabele verbergen. Soms leidt dit tot onverwacht gedrag, vooral bij multithreading.
let value = 10 let closure = { let value = 20; print(value) } closure() // 20 print(value) // 10
Kan je een constante en een variabele met dezelfde naam in dezelfde zichtbaarheid declareren?
Nee. Swift staat het niet toe om var en let voor dezelfde naam binnen één scope te hebben:
let x = 5 var x = 10 // Fout: Ongeldige herdeklaratie van 'x'
Hoe verwarring met shadowing van klasse-eigenschappen bij overerving vermijden?
Als een subklasse een eigenschap declareert met de naam van de ouder, gebeurt shadowing. Echter, bij toegang via super of self zal de overeenkomstige eigenschap worden gekozen. Het is beter om geen identieke namen onnodig te gebruiken.
In de klasse Account heeft een van de ontwikkelaars per ongeluk de variabele balance gebruikt als naam voor een functieparameter en binnen de functie opnieuw let balance = ... gebruikt. Door shadowing werd de berekening met een onjuiste waarde uitgevoerd en gaf de functie een onjuist resultaat terug, wat pas in een late fase van de testen aan het licht kwam.
Voordelen:
Nadelen:
Het hele team heeft afgesproken om prefixes te gebruiken (bijvoorbeeld inputBalance) of altijd self te gebruiken voor verwijzingen naar eigenschappen. Hierdoor zijn fouten door shadowing bijna verdwenen, en is het onderhoud van de code vereenvoudigd.
Voordelen:
Nadelen: