How do I modify the shadowed u inside the if-statement below?
func f () {
print (#function, "...")
var u: Int? = 29
if var u {
u *= u
print ("\tinner u", u)
// modify the outer u
// can't, because it is shadowed by the unwrapped u
}
print ("\touter u", u!)
}
Workaround:
func g () {
print (#function, "...")
var u: Int? = 29
let setu: (Int?) -> Void = {u = $0}
if var u {
u *= u
print ("\tinner u", u)
setu (u)
}
print ("\touter u", u!)
}
f ()
g ()
f() ...
inner u 841
outer u 29
g() ...
inner u 841
outer u 841
How useful would a feature like this really be? Being explicit under a different name established good intention. This feels like when one sometimes inadvertently shadows a property that can get mixed up with implicit self.
If you want to access the outer binding from the inner scope, then do not shadow it: if you shadow the outer binding, then it expresses your intention that it cannot be accessed from the inner scope—this is a feature.
I've always wanted this feature. I generally just name things uglier than I want. But that's probably a bad idea these days; practicing civil disobedience in one area of your life, working to make life look like you want it to, will help you make it a habit for where it counts more. The best way I know of to accomplish that is a struct instance.
func f() {
struct F {
var u: Int? = 29
}
var f = F()
if let u = f.u {
f.u = u * u
}
}
It seems to me that this would be a nice compromise?
func f() {
f: do {
var u: Int? = 29
if let u = f.u {
f.u = u * u
}
}
}
As I said, with your example, a user could no longer express that they do not intend access to the first binding to be possible within the inner scope. That is strictly less expressive than the current state of the language, where you can already accomplish what you want by giving the second binding a different name.
Anyway, I suspect this conversation is entirely played out. The question about how to do what you asked using Swift has been asked and answered.
There are many ways to evaluate language features, but two criteria are always at the top of my mind:
is this feature an abstraction (something that can decrease the complexity of your entire program by a non-constant factor), or is it syntax sugar (a local replacement of a token sequence with a slightly shorter one)?
do any other well-designed languages have anything similar?
If you’re adding well-worn abstractions and sugar, then you’ve got a body of prior experience to draw upon. Thinking of adding a novel abstraction? It may or may not work out, but someone has to move the state of the art forward; good luck to you! Novel syntax sugar on the other hand, is one of those things that almost never turns out to be a good idea in hindsight.
One feature that’s been discussed is support for inout bindings. The idea is that you’d be able to perform a scoped mutating access of some location. Writes to the binding would update the location. Eg,
var u: Int? = 27
if var u = &u { // or whatever
u *= u
}
This rationale is unconvincing to me. Nearly every time I see a binding shadowing another binding in Swift, the intention is to communicate "this is a non-optional version of the shadowed binding", not "I want to disallow access to the shadowed binding".
That being said, I don't think this feature would be useful enough to be worth adding, especially if we get inout bindings.