Background:
Shadowing is the phenomenon where a variable is declared with the same name in an inner scope, obscuring (shadowing) the variable from an outer scope. In early versions of Swift, the compiler was lenient regarding shadowing, but as the language model became more complex, explicit identification of such cases became mandatory to avoid bugs.
Problem:
Shadowing complicates code maintenance and introduces hard-to-trace errors — accidentally declaring a variable with the same name can lead to accessing a variable that the developer did not intend. This is particularly critical when passing variables by reference and inside loops or closures — often the errors manifest only at runtime.
Solution:
Swift allows variable shadowing, but it is recommended to avoid obscuring important variables/properties, to use different names, or to use explicit self/this references. Particularly in the initializers of structs/classes, it is advisable to use self to distinguish between the member and the parameter:
Code example:
struct User { let name: String init(name: String) { self.name = name // self ensures assignment clarity } }
Key features:
What happens with shadowing in loops and closures?
If a variable is declared inside a closure with the same name as in the outer context, shadowing will hide the outer variable. Sometimes this leads to unexpected behavior, especially with multi-threading.
let value = 10 let closure = { let value = 20; print(value) } closure() // 20 print(value) // 10
Is it possible to declare a constant and a variable with the same name in the same scope?
No. Swift does not allow having var and let for the same name within the same scope:
let x = 5 var x = 10 // Error: Invalid redeclaration of 'x'
How to avoid confusion with class property shadowing during inheritance?
If a subclass declares a property with the name of the parent, shadowing occurs. However, accessing through super or self will choose the corresponding property. It is better to avoid using the same names unnecessarily.
In the Account class, one of the developers accidentally used the variable balance as the name of a function parameter and inside the function again used let balance = .... Due to shadowing, the calculation was performed with an unintended value, leading the function to return an incorrect result, which was only discovered at a late stage of testing.
Pros:
Cons:
The entire team agreed to use prefixes (for example, inputBalance) or always apply self for property references. As a result, shadowing errors virtually disappeared, and code maintenance became easier.
Pros:
Cons: