`if let` shorthand

Please! This would be such an awesome ergonomic improvement. Xcode 13 adding autocomplete to if let foo = foo was a big improvement, but would still be so much better to not have the extra cruft. (And the fact that automatic tooling was added to compensate for something everyone types out regularly seems like a clear vote for this syntax in and of itself)

This feels like one of the last big head-scratching pain points of using Swift that virtually every developer encounters and would be a big win to implement.

I agree that the let seems important in declaration due to the potential conditional nature of an if statement that doesn't apply to for loops. I'm also not a big fan of a custom unwrap keyword, being able to unwrap an optional and check another condition in the same line is very nice in Swift currently and it'd be a shame to lose that.

I feel like if let foo is something every Swift developer has came up with in their head at some point (it feels like a monthly discussion on Twitter at times) and seems like an obvious/clear win.

8 Likes

It'd be nice if you also summarize what's been discussed so far (esp. the different syntaxes ppl have preferred) and, more importantly, what are you trying to add to the discussion. So far, it's still a repeat of past threads.

Edit:

Oh I see, you now add implementations. Still, it'd be nice if you discuss alternate spellings in the proposal (and why yours are superior).

3 Likes

That's the thing though. The left hand side is very different from the right hand side, which you'll notice if you use a new name.

I think something like if shadow makes much more sense. if let x { } looks fundamentally different from if let x = y { } even though they do the same thing. They both unwrap and assign a value, the difference is that the latter doesn't shadow the name.

But at the same time I don't think we need more syntax if we can avoid it.

I appreciate the effort of implementing this but I'm still not convinced we need it. if let x { looks fundamentally broken, what is a let binding doing on its own? If instead we were proposing to get semantic analysis (for example like typescript) it would be another story.

That said I imagine I wouldn't opposite very strongly if this ended up being officially proposed.

I'm not against this pitch in the form it is presented. Would just note that in this example:

if let someLengthyVariableName = someLengthyVariableName, let anotherImportantVariable = anotherImportantVariable {
    foo(someLengthyVariableName)
    anotherImportantVariable.bar(someLengthyVariableName)
}

rather than writing:

if let someLengthyVariableName, let anotherImportantVariable {
    foo(someLengthyVariableName)
    anotherImportantVariable.bar(someLengthyVariableName)
}

I would probably prefer something more concise anyway:

if let a = someLengthyVariableName, let b = anotherImportantVariable {
    foo(a)
    b.bar(a)
}

One also misses out on the ability to "jump to definition" (in Xcode) to locate the declaration for the RHS.

5 Likes

As someone always using the explicit self, I don't think I would use this shortcut.

For me, if let foo = self.foo is crystal clear and understandable even if you look at it years later. I don't mind repeating myself here.

9 Likes

IMO this is one of the strengths of this proposal. Variable names like a or b are cryptic and vague, which contradicts Swift’s goal of clarity at the point of use.

7 Likes

Some thoughts:

  1. The new syntax should be usable anywhere you can use if let foo = foo conditions today (if, else, guard, while), so if using unwrap we would likely want this to be:

    if unwrap foo { ... }
    guard unwrap foo else { ... }
    
  2. The new syntax should support the distinction between let foo = foo and var foo = foo. Including that would give us something like:

    if unwrap let foo { ... }
    if unwrap var foo else { ... }
    
    // or we could have `let` be the default
    // but let folks add `var` where necessary 
    if unwrap foo { ... }
    if unwrap var foo { ... }
    
  3. I personally think its preferable to draw from existing keywords and patterns rather than introduce a new keyword for this. I think if let follows naturally from the existing syntax, like how the existing syntax follows naturally from the long-form if case .some syntax:

    if case .some(let foo) = foo { ... }
    
    if let foo = foo { ... }
    
    if let foo { ... }
    
9 Likes

If a or b are too vague in this context, your if block is way too large for readability.

3 Likes

So generally I’m very supportive of anything making it easier to deal with optionals. However, I would want to know such a feature would not complicate or preclude a more comprehensive form of nil checking (as listed in the alternatives), as I feel that is something Swift needs. If this did restrict such future options I would give it a -1. If it works as a first step towards such nil checking then it's a +1

I think naming things short names that are no longer descriptive/indicative of what the variables do purely so you can save time writing unnecessarily verbose checks is a perfect example of why this proposal is needed.

6 Likes

I understand this is not everyone's cup of tea, but choosing between these two examples my personal preference would be for the latter:

if let someLengthyVariableName, let anotherImportantVariable {
    foo(someLengthyVariableName)
    anotherImportantVariable.bar(someLengthyVariableName)
}

I would probably prefer something more concise anyway:

if let a = someLengthyVariableName, let b = anotherImportantVariable {
    foo(a)
    b.bar(a)
}

perhaps not "a" and "b" per se, but normally I don't afraid of using names like "x" or "y" or "i" or "n" or "v" or "vc", or "nav", etc, as @Avi has pointed out the short context is the key ("7 line rule", etc).

Having said that, I still see the value of the proposal, just for me a better convincing example would be something with short names like:

if let one, let two {
    foo(one)
    two.bar(one)
}

rather than the one that uses very long names (in which case this proposal would be of no help for me).

"Clarity at the point of use" includes using short names, long names that are trying to be a mini description of what the thing is are way too noisy for me personally to be useful.

3 Likes

For me, it reads ambiguously because foo could be a Bool. I need to figure out the type of 'foo' before I understand whether the if statement is evaluating foo or creating an unwrapped constant foo. In the for-in case, it's not ambiguous.

4 Likes

I think this looks a bit broken at first. Defining a let without assigning anything to it seems odd to me personally. But I guess I could adopt to it if I have to.

It could even be an Optional bool :wink:

Presumably these ought to be else if.

1 Like

Haha, oops! Fixed, thanks :+1:

2 Likes

@cal

Happy to see this going forward.
Because I never omit type declaration, may I ask if this expression allowed with current implementation?

var someLengthyVariableName: SomeLengthyTypeName?

if let someLengthyVariableName: SomeLengthyTypeName {
    ...
}

Yes! That's supported by the current implementation.

1 Like