Storia della questione:
Lo shadowing è un fenomeno in cui una variabile viene dichiarata con lo stesso nome in un'area di visibilità interna, oscurando (sovrascrivendo) la variabile nell'area esterna. Nelle versioni precedenti di Swift, il compilatore era meno rigoroso riguardo lo shadowing, ma con il complessarsi del modello linguistico l'identificazione esplicita di tali casi è diventata obbligatoria per evitare bug.
Problema:
Lo shadowing rende difficile il mantenimento del codice e genera errori difficili da rilevare: la dichiarazione accidentale di una variabile con lo stesso nome può comportare che l'accesso avvenga non sulla variabile che il programmatore si aspetta. Questo è particolarmente critico nei casi in cui si passano variabili per riferimento e all'interno di cicli o chiusure: spesso gli errori si manifestano solo in fase di esecuzione.
Soluzione:
Swift consente lo shadowing delle variabili, ma si raccomanda di evitare l'oscuramento di variabili/proprietà importanti, di utilizzare nomi diversi o di utilizzare riferimenti espliciti a self/this. In particolare, negli inizializzatori di struct/class si consiglia di usare self per distinguere tra membro e parametro:
Esempio di codice:
struct User { let name: String init(name: String) { self.name = name // self garantisce chiarezza nell'assegnazione } }
Caratteristiche chiave:
Cosa succede con lo shadowing nei cicli e nelle chiusure?
Se si dichiara una variabile all'interno di una chiusura con lo stesso nome di quella nel contesto esterno, lo shadowing nasconderà la variabile esterna. A volte, ciò provoca comportamenti inaspettati, specialmente in situazioni di multithreading.
let value = 10 let closure = { let value = 20; print(value) } closure() // 20 print(value) // 10
È possibile dichiarare una costante e una variabile con lo stesso nome nella stessa area di visibilità?
No. Swift non consente di avere var e let per lo stesso nome all'interno della stessa area:
let x = 5 var x = 10 // Errore: Ridenominazione non valida di 'x'
Come evitare confusione con lo shadowing delle proprietà di una classe durante l'ereditarietà?
Se una sottoclasse dichiara una proprietà con lo stesso nome di quella del genitore, si verifica lo shadowing. Tuttavia, quando si accede tramite super o self verrà scelta la proprietà corrispondente. È meglio non usare nomi identici senza necessità.
Nella classe Account, uno sviluppatore ha accidentalmente utilizzato la variabile balance come nome per il parametro di una funzione e all'interno della funzione ha utilizzato di nuovo let balance = .... A causa dello shadowing, il calcolo è stato effettuato non con il valore corretto e la funzione restituiva un risultato errato, che è stato rilevato solo in una fase avanzata dei test.
Pro:
Contro:
Tutta la squadra ha concordato di utilizzare prefissi (ad esempio, inputBalance) o di applicare sempre self per fare riferimento alle proprietà. Di conseguenza, gli errori di shadowing sono praticamente scomparsi, rendendo più semplice la manutenzione del codice.
Pro:
Contro: