The Great var-vs-let War of 2016 Armistice

Prior to Swift’s open sourcing, SE-0003, which eliminated var from function parameters and pattern matching was accepted into the language for Swift 3.0.

Since then, the Swift community has pushed back and pushed back hard against this decision, particularly when using var in case pattern matching and if/guard/for statements.

Today, the Swift team issued a statement:

The core team met to discuss SE-0003, and we have a new conclusion, described below.  As was mentioned on the other thread, this proposal is a bit unusual because it predates Swift open source, and thus didn’t go through the full evolution process, nor did it get the normal public review that would come with it.

The core team broke this proposal down into a few different cases, each of which came to a different conclusion.  To be clear up front, this is not a clear-cut topic, and there are opinions on all sides.  Here are the decisions the core team came to, along with some rationale:

Parameter Lists

‘var’ in a parameter list is problematic for a number of reasons:
  • Parameter lists currently allow both “inout” and “var”, and real confusion occurs for some people learning swift that expect “var” to provide reference semantics.
  • Parameter lists are not “patterns” in the language, so neither “let” nor “var” really make sense there.  Parameters were patterns in a much older swift design, but that was eliminated a long time ago and this aspect never got reconsidered.
  • “var” in a parameter list is odd because it is an implementation detail being foisted on the interface to the function.  To be fair, we already have this with “API names” vs “internal names”, but this is a bigger semantic implementation detail.
Conclusion: The core team decided that we should REMOVE “var” and “let” from parameter lists. “var” in a parameter list is convenient sugar that defines away some minor boilerplate (the shadowing copy), however, the cost benefit tradeoff doesn’t pay enough to keep it.


“if var”, “for var”, “if case var” etc all use the pattern grammar (aka “pattern matching” and “destructuring” features described in TSPL).  We discussed whether to eliminate var from this, with much more mixed results:
  • We currently have a duality across the language between var and let which is common, unifying, and works really well in practice.  Eliminating var from pattern matching would make the language less uniform, because patterns wouldn’t align with var/let declarations.
  • Working in Swift *demands* that you get an early grasp on what value semantics means, and “var x = y” is always a copy of the value.  As such, based on the strong duality mentioned above, it is reasonable to expect people to learn that “if var x = y” produces a copy and not a reference binding.
  • There certainly is confusion from people who expect “if var” to do a reference binding, despite the comment directly above.  However, we feel that this is more of a point-in-time confusion than the parameter case, given that the parameter case exposes the ‘var’ as part of the function signature.
Conclusion: The core team decided that we should KEEP “var” and “let” in patterns.

Case Patterns

We had an additional discussion focused specifically on whether it would make sense to ban var in case patterns, e.g.: case .Foo(var x):
  • The core team agrees that this specific case is a common point of confusion, particularly because Swift doesn’t provide a way to get a mutable binding to the associated value in an enum.
  • That said, making a special case for this would make Swift less regular.
  • The core team decided to KEEP “var” here.
  • We will stop leading people into it by eliminating the “note: change ‘let’ to ‘var’ to make it mutable” note that the compiler produces for patterns.
Eliminating the note allows users sufficiently knowledgable about Swift to keep using it, but people who just mash the “fixit” button to silence the compiler won’t get surprising behavior.
-Swift Core Team

In the end, var will be removed from parameter lists, where it can confuse users with inout functionality1 but remain available for most other use cases, eliminating the labor of constantly using let binding followed by var binding.

Swift developers everywhere are celebrating this morning. Let us all raise a glass to the Swift Team in honor of this thoughtful reconsideration.

I am working on a proposal that will further simplify inout by moving it from the label side of declarations to the type side. Watch this space.


  • Have recently learned about companies/projects moving back to Objective-C after an unsuccessful attempt to move to Swift, which absolutely killed productivity (yes, some folks have actual work to do). Not surprised as the Swift team seems to have gotten so far away from developing a “general purpose” programming language. Lets not forget, some of us know how to code, and actually like to code, and don’t want or expect the compiler to do everything for us. Some of us “old school” developers ALWAYS CHECK FOR NULL (nil) and don’t need the compiler to do that. Although some productivity gains can be had by coding in Swift (less lines of code) , it does not counter the loss in productivity (time spent trying to satisfy the stupid compiler). Objective-C remains the safest/best/most-predictable bet for now.

    • I think those companies either jumped in too early (e.g., before Swift 1.2) and had a bad experience with the language. Either that, or they took the wrong approach in learning the language (e.g., trying to convert existing code bases without doing a dozen or so tutorial/sample projects to learn the differences in paradigms).

      On my end, I’ve done most of my coding in Swift for over a year now, and while the developer tools are not up to snuff when compared to the support that’s there for ObjC, I’ve been able to ship multiple high-visibility apps that are 100% swift without many issues at all.

      I’d suggest the those people give it another go, as Swift 2.0+ has been pretty damns stable (outside of issues with SourceKit when dealing with enumerated types).

  • like I have all day to type, add or remove ! and ? marks.

    85% of Swift does 100% of what I need.

    now give me all the proper bindings to all of Cocoa and the frameworks and go on vacation.

    Swifts ok. she’s cute and clever, can be annoying. but ‘oh the compiler she takes a lot of pleasing.

    Objective-C still rules in this camp. like Borat said: “It’s for men”.

    looking forward to Swift 3.1 … or whenever the binary cools down.

    • That sounds like a review in a 1960s car magazine. It’s a programming language, not a muscle car.

    • I sympathize with the need to maintain a stable code base. The point is more than fair, it’s unquestionable.

      But geez… the “you’re no programmer until you’ve endured everything I had to” chestnut? It’s a _tool for accomplishing things,_ not a fraternity hazing ritual.

      Assembly was hairy-chested. Then FORTRAN: coping with numeric literals with mutable values was Mastery. Then C; using a pointer to subscript through the entire memory space is darn handy, and if you overrun buffers just rub some dirt on it. I did, you can. Then macros, then having to visualize vtables to understand multiple inheritance, then lexical-substitution templates… Paged memory is a crutch for the weak-minded: Who needs dynamic loading when you have read() and function pointers? It was manhood for me. In 1981. Alas, after 35 years I must count my manhood cheap.

      In truth, you were just making a funny reference. You really have learned something since your entry-level job. Odd metaphor for a comment in the blog of a woman with near-godlike reputation, though.

  • So what about protocols requiring ‘var … { get }’ syntax for read only properties? Is there some sort of underlying reason for this confusing syntax instead of ‘let …’? Now that Swift allows deferred initialization of lets does this requirement make sense?

    • If I were you, I’d bring that up on Swift-Evolution.

    • “Not settable” and “invariant” are orthogonal concepts. A simple example would be a timer, whose elapsed-time property changes at every reference. `let` means “constant at every reference.” I can imagine other interpretations, but it’s moot: TSPL used `let` and `constant` as synonyms from the start.

  • Yet another reason that I just keep on using Objective-C for most of my work. Someone, please let me know when Swift is out of Beta, thanks. I have far too much actual WORK to do, for all of this stuff. (Sorry if I sound snarky, but it’s a real world out there, with real deadlines and real bank managers and real customers and clients. They don’t care about real-time Swift language evolution. And I want tools that WORK when I expect them to work.)