[swift-evolution] Proposal Sketch: simplify optional unwrapping syntax

ilya ilya.nikokoshev at gmail.com
Fri Dec 11 11:30:30 CST 2015


> 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.

I'm a bit surprised you have a code with non-trivial code paths for both
optional and non-optional values of some computations. Could you perhaps
provide an idiomatic example of such a function?


On Fri, Dec 11, 2015 at 8:17 PM, Daniel Hooper via swift-evolution <
swift-evolution at swift.org> wrote:

> 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.
>
> I didn't say we should remove if/guard let. They would stay.
>
> 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.
>
> 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.
>
> On Fri, Dec 11, 2015 at 11:41 AM Sean Heber <sean at fifthace.com> wrote:
>
>> 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:
>>
>> For example:
>>
>> var x: MyType?
>>
>> with x {
>>   x.someFunction()              // okay - this entire block is skipped if
>> “x” is nil anyway
>> }
>> x.someFunction()                // not okay as-is since x is optional
>>
>>
>> Using the definition  of “with” from Erica’s Method Cascading proposal
>> https://gist.github.com/erica/6794d48d917e2084d6ed, you could even drop
>> the variable reference itself from inside the block body:
>>
>> with x {
>>   someFunction()                // would call “someFunction()” on “x”
>> }
>>
>>
>> And I’d additionally propose that if you wanted to replace if-let-else,
>> you could potentially do this:
>>
>> if with x {
>>   // x is known non-nil
>> } else {
>>   // x is known to be nil
>> }
>> // x is optional and nil-ness is unknown
>>
>>
>> l8r
>> Sean
>>
>>
>> > On Dec 11, 2015, at 10:28 AM, Marc Knaup via swift-evolution <
>> swift-evolution at swift.org> wrote:
>> >
>> > One problem with dropping if/guard let is something like this:
>> >
>> > if let x = a?.b.c?.d, y = something(x) {
>> >    …
>> > }
>> >
>> > would then have to become this:
>> >
>> > let x = a?.b.c?.d
>> > if x != nil {
>> >    let y = something(x)
>> >    if y != nil {
>> >        …
>> >    }
>> > }
>> >
>> > I'm fine with
>> >    if let x
>> > as a shortcut for
>> >    if let x = x
>> >
>> > It just reads a bit weird - like declaring an immutable variable with
>> no type and no value.
>> >
>> >
>> > On Fri, Dec 11, 2015 at 5:19 PM, Jeff Kelley via swift-evolution <
>> swift-evolution at swift.org> wrote:
>> > 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:
>> >
>> >       if let foo = foo { /* use foo */ }
>> >
>> > could become this code:
>> >
>> >       if let foo { /* use foo */ }
>> >
>> > 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.
>> >
>> >
>> > Jeff Kelley
>> >
>> > SlaunchaMan at gmail.com | @SlaunchaMan | jeffkelley.org
>> >
>> >> On Dec 11, 2015, at 11:11 AM, Daniel Hooper via swift-evolution <
>> swift-evolution at swift.org> wrote:
>> >>
>> >> 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:
>> >>
>> >> if let nearestX = nearestX { closest = nearestX }
>> >> guard let layer = layer else { continue }
>> >> // use layer
>> >>
>> >> 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.
>> >>
>> >> The solution:
>> >> 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.
>> >>
>> >> if nearestX != nil { closest = nearestX } // notice that nearestX
>> isn't force unwrapped
>> >> guard layer != nil else { continue }
>> >> // use layer, without force unwrapping
>> >>
>> >> Why force unwrapping isn't a good alternative:
>> >> 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:
>> >>
>> >> {code:java}
>> >> if layer != nil {
>> >> // lots of code before //
>> >> layer!.backgroundColor = newColor
>> >> // lots of code after //
>> >> }
>> >> {code}
>> >>
>> >> 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.
>> >>  _______________________________________________
>> >> swift-evolution mailing list
>> >> swift-evolution at swift.org
>> >> https://lists.swift.org/mailman/listinfo/swift-evolution
>> >
>> >
>> >
>> > _______________________________________________
>> > swift-evolution mailing list
>> > swift-evolution at swift.org
>> > https://lists.swift.org/mailman/listinfo/swift-evolution
>> >
>> >
>> >  _______________________________________________
>> > swift-evolution mailing list
>> > swift-evolution at swift.org
>> > https://lists.swift.org/mailman/listinfo/swift-evolution
>>
>>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20151211/e05e01e8/attachment.html>


More information about the swift-evolution mailing list