That just gives you more leeway to show a. (in addition to b.), no? ;)
Only from curiosity:
Isn't this (repeated) proposal only a symptom of the missing flow-sensitive typing, is it?
Changing this typing sounds not simple, but very complex, I guess :)
Regarding flow-sensitive typing, see up thread: `if let` shorthand - #62 by Ben_Cohen
Mostly, people caveat some of their opinions with "I think" or "It seems". I do so liberally in this thread. But it becomes very tedious to read if you do it constantly in every sentence (even with abbreviations like "IMO"), so sometimes a statement is left bare. When this happens, it is best not to latch on to it and complain that this particular thing has been stated "as fact". It is clearly someone's opinion when viewed in context.
For example:
No caveat here â you seem to be stating it will cause a lot of bugs as a fact. But of course you aren't â everyone understands that this is just your opinion. But the words used here are extreme. It will introduce a lot of bugs? The var
in if var x
is "nearly invisible"? This is clearly hyperbole (IMO of course) and I think the discussion would be better without extreme characterizations like this.
What (I think!) you mean is that you can envision a hypothetical scenario in which someone might think it's an inout binding and that this could lead to a bug occasionally. And I in turn think that this is not going to be a problem in practice. Nowhere else in the language does var
do this, including the very similar if var x = x
that already exists. And current use of that feature does not suggest this problem is causing "a lot of bugs" as far as I know.
This is a phenomenon we get a lot on these forums, which I call "performative misunderstanding", where a possible but frankly implausible misinterpretation is cited as a reason not to adopt a feature. I think it's a real problem, because it worsens good proposals, for example giving us waffly names for standard library functions. It can cause us to skew the design towards the very first use of a feature, not the subsequent 1,000+ uses, all the while not actually making that first use particularly better.
I wouldn't. I'm not suggesting we accept a proposal without considering how the future direction of borrows and moves might interact with it â though I do think you're overestimating the closeness of the design of type-system-level moves and also the likelihood it will affect this particular sugar.
What said in the text you quote is that to keep this discussion on track and hopefully converge on a proposal we could run is that we first discuss the language as it is today, and then once settled on a good potential addition, we think about its interaction with future syntax for borrows.
I also think there is a flip side to the "we've done without this for 7 years"... which is that we should be a bit sheepish about that. It's not great that this clear pain point has gone unaddressed so long, and putting it off another two years because it might not quite fit with a feature that hasn't really been designed or pitched yet is not OK. What we will probably need to do is make a judgement call about the likelihood of future directions clashing, maybe with some early sketches of what that feature might look like. But that is going to be a long and probably pretty hand-wavy discussion, and I think it's best had after we handle the already hard-enough task of settling on a proposal that works for the Swift of today.
I fear âperformative misunderstandingâ implies an intent to deceive. But you have very clearly highlighted a pervasive tendency in design discussions that Iâve seen here and elsewhere. I think it stems from a well-placed concern about âwhat if we get this wrongâ? But this fear turns the process on its head. In my experience, the best designs emerge from a focus on self-consistency, conceptual thoroughness, and approachability. Not from future-proofing or avoiding interactions with other features.
In this case, we have a very clearly defined problem: the verbosity of optional unwrapping syntax discourages people from using descriptive variable names. @cal made a targeted concrete proposal: drop the duplication of the variable name, but retain the existing syntax. A bunch of concerns and alternatives have been raised, but as they have trended toward the more esoteric (e.g. new keywords) they have lost sight of the benefits of the original targeted proposal.
Yes this is a good summary of how I feel. My intention is not to imply bad faith, but rather to characterize a trap it is easy to fall into where excessive focus on downsides that aren't actually a concern in practice ends up worsening proposals.
I hope youâd also agree that not all forward-looking criticisms fall into this category. For example, I think it was fair for @Chris_Lattner3 to bring up if var
and mutable reference bindings, if only to ensure they are contemplated. Theyâre âreal enoughâ that the pitch can foresee potential conflicts or ambiguities. But that doesnât need to dominate the discussion, dooming the original pitch and diverting attention to a new alternative that drops all the original pitchâs benefits in favor of avoiding any potential conflict.
To address the proposed alternative spelling:
One of the key behaviors of optional unwrapping is that it creates a new variable defined within the inner scope. When deciding what spelling to use for this shorthand, my top priority is making it as clear as possible that a new variable is being defined.
Since we use let
/ var
for this elsewhere in the language, I think if let foo
makes the variable scoping behavior reasonably clear and unambiguous. For if unwrap foo
, I personally don't think it is "obvious" whether or not a new variable is defined for the inner scope. This can be learned / memorized of course, but I think this is the main downside of introducing a new keyword compared to leaning on existing keywords / concepts.
Another reason I think let
/ var
is a good idea is that it makes the UX limitations a bit more intuitive. For example, it is not necessarily obvious that if unwrap foo.bar
would be invalid. On the other hand, it is somewhat intuitive that if let foo.bar
would be invalid (e.g. that let
can only be followed by an identifier and not an expression) since this is the case elsewhere in the language.
Some other points that folks have mentioned that I agree with:
How about for x in y
?
While I do believe the effort of changing the if let
construct is not worth the rather minimal gains (if any!), there are precedents in the language when brevity was more important than spelling out/suggesting each step the compiler takes when translating the statement. And they work quite well, nobody's complaining why we don't use for let x in y
.
Yep, for foo in bar
is one exception where we don't use let
to introduce a new variable. Although imo this is because for in
is a "term of art" present in a large number of languages and the creation of a new variable in the inner scope is clear by convention. Adding a let
wouldn't really add much additional clarity.
We likely do need some keyword for optional unwrapping conditions, to avoid ambiguity with boolean conditions:
So in this case the let
(or some other keyword) is pretty important:

if foo, let bar { ... }
An alternative to a keyword is a sigil, as in:
if foo?, let bar = foo.bar {
âŚ
}
But I agree with your rationale for wanting let
to appear in the unwrapping expression. It succinctly explains the shadowing behavior, which I donât think any Swift programmer should be afraid of or averse to.
By the way, in the case of a multi-term defeatable condition, the shadowing caused by unwrapping would take effect for the rest of the expression, right? Otherwise Iâd have to write (using my personally preferred syntax variant) if let foo?, let bar = foo?.bar { }
.
My thoughts on this remain similar to what I had to say last May:
Overall,
if let x { ... }
feels like a good (new) balance of brevity and clarity. It maintains the existing 'if let
' phraseology that I expect most Swift programmers have come to instinctively understand as "bind if non-optional," and the additional behavior is (IMO) easily explainable. It feels so natural to me that I semi-frequently find myself writing it and getting a syntax error before remembering that it's not already supported!
Since I haven't seen it otherwise mentioned in this thread, I'll also resurface what I think is important precedent in the language for having special language support for the "initialize a new binding that shadows an existing binding with the same name". We already allow this for closure capture lists:
As for "omit[ting] the action," we already have another place where we allow a variable name on its own to be expanded to an initialization of a new variable with the same name:
let closure = { [x] in // implicitly: 'let x = x' ... }
This works even if
x
refers to e.g.,self.x
in the outer scope.
So we aren't inventing an entirely new concept here.
As for if let x {
vs. if let x? {
: as noted above, I think if let
already serves as a pretty strong indicator to Swift programmers that there's an optional unwrap happening, but the signal may not be as strong for, say, if var
(or future if inout
, if ref
) unwrapping shorthand. So perhaps that's a case for requiring the trailing question mark, though also maybe those uses won't be common enough to justify 'muddying' the overwhelmingly common if let
case. I think I have a weak preference for if let x?
but could very likely be happy with either in the language.

nobody's complaining why we don't use
for let x in y
.
As a Swift newbie coming from C++, that lack of let there actually confused me for a while wondering if using an existing local variable there reused it or shadowed it as I'm so used to for (int i = 0; i<n; i++)
vs for (i = 0; i<n; i++)
As a Swift newbie coming from C++, that lack of let there actually confused me for a while
Fair enough, but my point is, people learn about it and carry on. I feel the brevity keeps on giving, while knowing there's an actual copy there it's a one time info which you don't necessary need to be reminded every time.
I must be on another planet as almost everyone posting here, because if let foo { ... }
to me looks dreadful.
I always read let a = b
with "let" being a verb, as in Pythagoras declaring "let c be the triangle's hypotenuse" (although he'd be speaking Greek.. so bad example, but YKWIM). This reading doesn't really fit with "var", but I regard "var x" to be a term of art and read var x = y
kind of as if it were let var x = y
.
There are a few cases in Swift where one uses a loose "let foo":
-
let foo: Int
: I read these as "let foo be an Int (defined below)" which is a reading that's helped by there always being a type after the colon -
case .cat(let curiosity)
in a switch or "if case" expression: these straight up give me cognitive dissonance and makes me wish the language did matching expressions differently. It's a red flag to me that these expression need to be mentally parsed at a more-conscious level. [1] -
are there more I've forgotten about?
Contrary to people who've relayed their experiences teaching others, if let a = b
made sense to me right off the bat: "if I'm able to let a equal optional value b". I feel the part about unwrapping is implicit compared to simply let a = b
by being within an "if" expression, Sure, not obvious when you don't already know the idiom, but once you do I don't think there's any cognitive dissonance.
However if let foo
looks like nothing to me. It adds yet another loose "let foo" to the language, one that would be used a heck of lot more than the cases noted above. To me it takes the cognitive dissonance of the lesser-used "case let" expressions and moves it to prime time.
Perhaps other coders in the thread read let a = b
as immutable a = b
, where "immutable" is an adjective (or whatever) instead of a verb, more akin to the plain reading of var x = y
. Maybe this allows if let foo
be less dissonant: "if I can make an unwrapped immutable variable out of optional value foo", or something. Or perhaps others aren't mentally mapping the code to English prose to the degree I do, and are just manipulating symbols.
The only two options I've seen in this thread that read acceptably to me are:
-
if unwrap foo
: Plain. As. Frickin'. Day. [2] -
if let foo = _
: It probably depends on whether one thinks "_" means "something unsaid" or "don't care", and only making sense if you think the former not the latter. I don't think Swift uses "_" on the RHS in any other case, so free to indicate something new along the lines of "something unsaid", namely "the same symbol as on the LHS". Also as unclear to beginners asif let a = b
is, surely more so in fact, but still comprehensible in my eyes after knowing the idiom.
-
Don't get me started on how "if case pattern = thing" is backwards, after all I write "if thing < 5" rather than "if 5 > thing", why can't write something like "if thing matches pattern"? To say nothing of "if foo is in collection" rather than "if collection contains foo" âŠď¸
-
but not "if unwrap a = b", again reading "unwrap" as a verb applied to a, not as just an available symbol indicating something about unwrapping âŠď¸
As long as there will be a construct for optional binding condition, there will be a learning curve for it, whatever syntax and semantics would be. We've learned if let x
, and it happened we often use it to explicitly shadow the optional variable - as if let x = x
. The proposal is pure evolutionary in that regard (with all its pitfalls), addressing what is recognized after the years of the use as verbose / noise. With the proposed syntax (and semantics untouched), I don't think the learning curve will be worsen. Sure it won't be improved but that is not the goal here. For those who learned the current syntax and semantics of the optional binding condition, they will likely use the proposed shorthand with the very same "correctness". I like how the proposed (subtle) change in the grammar hit the nail on the head - applies to all conditional control flow statements and preserve let and var. Personally I don't have a strong preference if I want it or not, or with if let foo?
spelling. I can definitely live without it, but if it will be implemented, I'll use it.
unwrap
keyword, borrowed values, and questioning the actual optional binding condition sound rather like revolutionary thoughts. They definitely shouldn't be dismissed but perhaps developed in another thread. If they will materialize, they won't challenge the proposal but will go even beyond optional binding conditions.
The unwrap
notion inspires operators that I call peel
and peel?
.
if peel? x {
is essentially the same as if unwrap x {
. Let me know
what you think about peel
.
The peel
operator works roughly like with
in Pascal. For any
struct/class x
, peel x
introduces a new scope that binds each member
name in x
to a copy of the member's value in x
.
The peel?
operator removes a level of Optional<>ity. It is used in
if
or guard
conditions. For any optional x == .some(y)
, peel? x
is true; it introduces a new scope where x
is bound to a copy of y
.
For any optional x == nil
, peel? x
is false.
Under at least one circumstance it makes sense for peel
and
peel?
to compose: if peel peel? x {
. I believe it makes sense
for there to be any number of ?
after peel
: peel???
for
Optional<Optional<Optional<_>>>
.
Examples:
struct Record {
var a: Int
var b: Int?
}
struct CompoundRecord {
var c: Record
var d: Int
}
let compound: CompoundRecord
let rec: Record
let optRec: Record?
let y: Int
let z: Int?
if peel rec { // error: `peel rec` always succeeds
}
peel rec {
// In this scope, a and b are copies of rec.a and rec.b, respectively.
}
peel y { // error: `y` has no members
}
peel? y { // error: `y` is not Optional<>
}
peel z { // error: `z` has no members
}
peel? z { // error: `peel? z` can fail
}
peel optRec { // error: `optRec` has no members (it is Optional<>)
}
if peel? z {
// In this scope, z in the outer scope is shadowed by a non-optional
// copy.
}
if peel? optRec {
// In this scope, optRec in the outer scope is shadowed by a
// non-optional copy.
}
if peel? optRec, peel optRec {
// In this scope, optRec in the outer scope is shadowed by a
// non-optional copy.
//
// Also in this scope, a and b are copies of optRec.a and optRec.b.
}
if peel? rec.b {
// In this scope, b is a copy of rec.b!.
}
if peel? optRec?.b {
// In this scope, b is a copy of optRec!.b!.
}
if peel peel? optRec {
// `optRec` is not shadowed in the inner scope.
//
// Also in this scope, a and b are copies of optRec!.a and optRec!.b.
}
if peel compound.c {
// In this scope, a and b are copies of compound.c.a and compound.c.b.
}
Dave

I believe it makes sense
for there to be any number of?
afterpeel
:peel???
for
Optional<Optional<Optional<_>>>
.
I think this would be an ergonomic non-starter as a replacement for if let x = x?.y?.z
, as the current construct automatically removes every level of optionality.
I do like how the two uses of peel
have a certain underlying similarity, as Optional<T>
is a kind of wrapper over T
, which means that peel?
would be peeling away the optional and leaving just the T
value. I fear, though, that this would be too subtle for people to understand.
Sounds like there is:
a) Some opposition to adjusting this syntax at all. This opinion appears to be in the minority, although I do admit, judging that by this thread alone is the definition of confirmation bias. So it seems to me that those opposed to sugaring this syntax could "just not use it" (and enforce that by lint rules if desired).
b) Some opposition to sugaring both if var x
and if let x
. I would actually like to understand this better. It seems @Chris_Lattner3 is trying to make a point there about lifetimes and ownership that I don't understand â I would really appreciate an elaboration on potential issues surrounding if var x
and move-only types or other ownership annotations.
c) A great deal of enthusiasm for if let x
in general, and a rejection of alternate spellings, e.g. if unwrap
, mostly for reasons of consistency (reasons I happen to strongly agree with).
My personal take is that if let x
would be greatly appreciated, but not life changing. In particular, I could take or leave if var x
, personally, but from here I'd lean towards including it for the sake of consistency (notwithstanding potential issues with upcoming ownership features).
edit: I would like to add that I don't agree with arguments against if let x
that claim if let
itself is bastardisation of pattern matching. That may be the case, but I have been a heavy user of Swift since v1 and I have not once thought of if let
in any relation to pattern matching. To me it is a syntax of its own.
I must say I am surprised and disappointed to see this discussion become so heated at times. I appreciate everyone's passion for getting this right, but I'd encourage everyone to take a step back and try to acknowledge that we're all trying to move in a positive direction.

So it seems to me that those opposed to sugaring this syntax could "just not use it" (and enforce that by lint rules if desired).
Not to comment on other parts of the reasoning, nor the opinion being expressed, but I loathe the "Just don't use it" argument with passion:
This argument only works when you live in a vacuum. We don't. I either leave or stay with the codebase that uses it, much to my own detriments.
Furthermore, it's dismissive and very disengaging. It says at least as much as
- "I agree that it's a problem, but"
- "I'm not going to do anything about it."
If it's not that big of a problem, convince me. If it can be alleviated, please do so. Such an answer doesn't move the conversation forward and simply leaves me out of the equation.
If it's really that good of an idea, then we can do better.