<div dir="ltr"><div>I don't think we should discuss "with" here as that is a separate proposal. I'm trying to draw attention of the approach of Swift generating shadow variables for you when an optional has been proven to be non-null. <br></div><div><br></div>I didn't say we should remove if/guard let. They would stay.<div><br></div><div>My proposal is to improve readability and reduce verbosity by generating shadow variables after "x != nil" checks. The "with x {}" and "if let x {}" approaches only reduce verbosity, at the additional cost of adding new keywords or syntax to the language, and do not really improve readability. Due to this, generating a shadow variable after "x != nil" is the most straightforward, lowest impact and readable approach.</div><div><br></div><div>ilya, you bring up a good point about "create shadow->write to original->read shadow" situations being potentially confusing. However "if let x = x" is very common in situations that this isn't an issue: taking a quick look at my code, 50% of all "if/guard let x = x" are on local variables that cannot possibly change out from under the shadow variable. If that could lead to confusion in a given situation, you could fall back on "if let x = maybe_x" to make it clearer that you're operating on a copy of a variable that won't change out from under you. Alternatively, the "if x != nil { x.bla() }" syntax could only be allowed on optionals in the current function scope.</div></div><br><div class="gmail_quote"><div dir="ltr">On Fri, Dec 11, 2015 at 11:41 AM Sean Heber <<a href="mailto:sean@fifthace.com">sean@fifthace.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">This has come up a few times. I’ve thrown my 2cents into a variant of “with” to solve this rather than messing with the meaning of if-let:<br>
<br>
For example:<br>
<br>
var x: MyType?<br>
<br>
with x {<br>
x.someFunction() // okay - this entire block is skipped if “x” is nil anyway<br>
}<br>
x.someFunction() // not okay as-is since x is optional<br>
<br>
<br>
Using the definition of “with” from Erica’s Method Cascading proposal <a href="https://gist.github.com/erica/6794d48d917e2084d6ed" rel="noreferrer" target="_blank">https://gist.github.com/erica/6794d48d917e2084d6ed</a>, you could even drop the variable reference itself from inside the block body:<br>
<br>
with x {<br>
someFunction() // would call “someFunction()” on “x”<br>
}<br>
<br>
<br>
And I’d additionally propose that if you wanted to replace if-let-else, you could potentially do this:<br>
<br>
if with x {<br>
// x is known non-nil<br>
} else {<br>
// x is known to be nil<br>
}<br>
// x is optional and nil-ness is unknown<br>
<br>
<br>
l8r<br>
Sean<br>
<br>
<br>
> On Dec 11, 2015, at 10:28 AM, Marc Knaup via swift-evolution <<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>> wrote:<br>
><br>
> One problem with dropping if/guard let is something like this:<br>
><br>
> if let x = a?.b.c?.d, y = something(x) {<br>
> …<br>
> }<br>
><br>
> would then have to become this:<br>
><br>
> let x = a?.b.c?.d<br>
> if x != nil {<br>
> let y = something(x)<br>
> if y != nil {<br>
> …<br>
> }<br>
> }<br>
><br>
> I'm fine with<br>
> if let x<br>
> as a shortcut for<br>
> if let x = x<br>
><br>
> It just reads a bit weird - like declaring an immutable variable with no type and no value.<br>
><br>
><br>
> On Fri, Dec 11, 2015 at 5:19 PM, Jeff Kelley via swift-evolution <<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>> wrote:<br>
> I’ve had similar ideas to this. Instead of ditching the if let syntax altogether, another approach would be to use the existing name if no new name is given, so that this code:<br>
><br>
> if let foo = foo { /* use foo */ }<br>
><br>
> could become this code:<br>
><br>
> if let foo { /* use foo */ }<br>
><br>
> In both cases, foo is non-optional inside the braces. If you gave it another name with the if let syntax, that would work as it does today.<br>
><br>
><br>
> Jeff Kelley<br>
><br>
> <a href="mailto:SlaunchaMan@gmail.com" target="_blank">SlaunchaMan@gmail.com</a> | @SlaunchaMan | <a href="http://jeffkelley.org" rel="noreferrer" target="_blank">jeffkelley.org</a><br>
><br>
>> On Dec 11, 2015, at 11:11 AM, Daniel Hooper via swift-evolution <<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>> wrote:<br>
>><br>
>> A very common pattern in swift code is to "guard let" or "if let" optionals - this works by creating a new non-optional variable to be used by future code. Often, the new variable is given the same name as the original optional variable, creating a shadow variable. This approach leads to odd looking code like this:<br>
>><br>
>> if let nearestX = nearestX { closest = nearestX }<br>
>> guard let layer = layer else { continue }<br>
>> // use layer<br>
>><br>
>> At a glance, and to Swift newcomers, this code looks completely non-sensical. It's also verbose for simply ensuring the variable is non-nil.<br>
>><br>
>> The solution:<br>
>> Swift should generate unwrapped shadow variables after nil checking. The compiler would treat the below code as if it had created an unwrapped shadow variable.<br>
>><br>
>> if nearestX != nil { closest = nearestX } // notice that nearestX isn't force unwrapped<br>
>> guard layer != nil else { continue }<br>
>> // use layer, without force unwrapping<br>
>><br>
>> Why force unwrapping isn't a good alternative:<br>
>> You might suggest force unwrapping variables when they're inside an if or after a guard that checks for nil. While this does allow for the "layer = nil" syntax, it results in code that is less resilient to change. Imagine that this code was written:<br>
>><br>
>> {code:java}<br>
>> if layer != nil {<br>
>> // lots of code before //<br>
>> layer!.backgroundColor = newColor<br>
>> // lots of code after //<br>
>> }<br>
>> {code}<br>
>><br>
>> And much later, you need to use some of the the code in the if body elsewhere, so you copy and paste a huge chunk of it. You likely won't notice the force unwrap, and unless you're lucky, you probably didn't paste it into an if that checked layer for nil. So you get a crash. Because of this, it's important we make safe optional unwrapping as easy and sensical as possible, and minimize the situations that you would need to force unwrap.<br>
>> _______________________________________________<br>
>> swift-evolution mailing list<br>
>> <a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a><br>
>> <a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br>
><br>
><br>
><br>
> _______________________________________________<br>
> swift-evolution mailing list<br>
> <a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a><br>
> <a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br>
><br>
><br>
> _______________________________________________<br>
> swift-evolution mailing list<br>
> <a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a><br>
> <a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br>
<br>
</blockquote></div>