Should using a property, regardless of whether it is stored or computed, indicate O(1) access? If not, why?
- Propose it
- Don’t propose it
Thank you for your insight.
Should using a property, regardless of whether it is stored or computed, indicate O(1) access? If not, why?
Thank you for your insight.
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.Patterns
“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.
Conclusions:
- 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.
1 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.
This happened:
And then I found this:
Objective-C expression evaluation implicitly imports all modules that were imported in the source context where execution takes place, providing a much higher fidelity debugging experience. In most cases this change eliminates the need to manually import modules while debugging. For example, using expr — @import UIKit that was commonly used to ensure that SDK declarations were available is no longer necessary. (11609847)
I had already imported UIKit into a playground module, so I didn’t need to re-import it into my Xcode 7.3/Swift 2.2 main playground page.
Kevin Lacker writes on the Parse blog,
We have a difficult announcement to make. Beginning today we’re winding down the Parse service, and Parse will be fully retired after a year-long period ending on January 28, 2017. We’re proud that we’ve been able to help so many of you build great mobile apps, but we need to focus our resources elsewhere.
We understand that this won’t be an easy transition, and we’re working hard to make this process as easy as possible. We are committed to maintaining the backend service during the sunset period, and are providing several tools to help migrate applications to other services.
Parse will release a database migration tool and will open source ParseServer. Regardless, this is going to come as a blow to a large segment of the iOS developer community.
More details at the New York Times.
As many of you know, I had been planning a Webcast series starting in a few weeks. Pearson’s downsizing has forced those to be cancelled.
Chris “Best Development Editor Ever” Zahn, my point person for the Content Update Program (CUP), has left Pearson as well to my great sadness. I’m assured that CUP isn’t going away and I’ll be meeting next week to try to push forward with it.
A ridiculous amount of mailing list effort has gone into discussion of SE-0023 API Design Guidelines. You’ll find the original guidelines here at swift.org, and I highly recommend you pop over and read them. For the most part, I really like the guidelines. I also think some bits about naming and labels are too prescriptive.
The document is broken into four parts: fundamentals, naming, conventions, and special instructions. I have basically no issues with the fundamentals: be clear, prefer clarity to brevity, comment everything. I’ve written Swift Documentation Markup, a book that takes these to heart and expands on how you can do this. Same no-issue stand applies to section four, special instructions.
The second section focuses on naming. Part one “promoting clear usage” says: avoid ambiguity by adding just enough words, cut away words that aren’t needed, augment weakly typed parameters with a role noun. I don’t have any problems with this part, and I could see myself diving in and exploring the philosophy more. The third part “use terminology well” is also innocuous.
Part two of naming though is “be grammatical” and I have quibbles with this section. I think Apple would be well served with just dumping it entirely. I started writing up a long, exhaustive response to this part but it started spiraling out of control.
The issue lies in what distinguishes naming things: should you name noun-y things with nouns and verb-y things with verbs? That’s probably the best approach, honestly, and one that would avoid the well-intentioned details in the current guidance.
Or should you evaluate whether methods mutate instances? Should you take all side effects into account and differentiate them from pure functions? And that doesn’t even take property-vs-method naming into account (not to mention any naming that might hint at complexity).
I honestly think Apple should drop this section like a hot potato rather than trying to force it to work with their current stab at it.
I also have issues with Conventions, specifically the bit about argument labels. Again, I’ve written up an overwhelming response over at github, where I make a case for why logically related arguments should weigh more heavily than the “drop the first argument” approach and why groups of related calls should emphasize their connection using initializer-like naming.
I currently have nearly a book’s worth of notes about these kind of issues, because I was planning on putting together a small self-pubbed book about Swift Style that I started working on earlier this winter. I got diverted by the the SE-0023 review but now I think I’m going to go back and start kicking away at my take on this again.
You can find some of these guidance posts here:
etc. etc.
All hail Xcode Beta 7.3 and Swift 2.2. It’s here and there’s so much in there. Here’s a first take at some of the major 2.2 features.
Like my posts? Consider buying a book or two. Thanks!
Doug Gregor proposed SE-0001, which allows using (most) keywords as argument labels. As a consequence, argument labels and parameter names can now be any keyword except `var`, `let`, or `inout`.
The compiler now automagically warns you about, for example, `defer`
in this screenshot. It provides a built-in fixit to change the external label to defer
.
Note that Xcode makes no exceptions for , no matter whether you’re a nudist, letting agent, or pirate. “Vaaaaaarrrr, me hearties!”
myFunction(inout: NavelType, let: Rental, and var: PirateCall)
Chris Lattner has gone to war against ++ and –, via SE-0004. He writes, “Code that actually uses the result value of these operators is often confusing and subtle to a reader/maintainer of code. They encourage “overly tricky” code which may be cute, but difficult to understand….While Swift has well defined order of evaluation, any code that depended on it (like foo(++a, a++)) would be undesirable even if it was well-defined…these fail the metric of “if we didn’t already have these, would we add them to Swift 3?””
The release notes say, “As a replacement, use x += 1 on integer or floating point types, and x = x.successor() on Index types.” The biggest choke point for this is usually in loops and at return points. If you have a postfix increment or decrement that looks like this:
return foo++
refactor with defer
{ defer {foo += 1} ... return foo }
For prefix increment, like return --foo
, just prepend the return:
{ ... foo -= 1; return foo }
You obviously don’t have to put both items on a single line the way I did here.
Never for;;get. Never surrender. Start refactoring your loops. They are deprecated in 2.2 and scheduled for removal in Swift 3.0.
Many loops can simply be expressed as for-in. (The Swift team is working on enhancing performance for these.) Others with complex conditions and side effects will need more tender care. Don’t forget that Swift supports labeled breaks and continues:
Important, especially for larger groups, Swift 2.2 introduces the new build configuration #if swift(>=x.y)
via SE-0020. This enables you to provide language-specific blocks so your code breaks less. Unfortunately, it’s not exactly working just yet:
Reimagined Currying
As the screenshot above shows, Swift 3 will also remove currying. I dived into this issue in my Bidding Farewell to Currying post. As you see at the bottom of the post, moving to a non-curried version is actually no big deal, and retains all the benefits of the special-form code. This update is courtesy of Joe Groff’s SE-0002.
Failable and Throwing Init Escape Clause
Designated initializers can now exit before initializing stored properties and/or calling super-init, a welcome relief for those who didn’t know why, when an initialization was going to fail, they still had to do all the “paperwork” of setting up an instance that would never be used.
Tuple Comparisons
Thank Lily Ballard for this great tweak courtesy of SE-0015. You can now compare tuples of Equatable and Comparable elements, up to 6 members at a time.
Beta 2 introduces three new structured markup keywords (I’ll get these into a Swift Documentation Markup update for iBooks within the next day or so.) Welcome - keyword:
, - recommended:
, and -recommendedover:
.
This is great stuff and I look forward to seeing the markup tags grow to match the current sets of semantic decorations currently used in other systems like Doxygen, JavaDoc, ReStructured Text, etc.
anyGenerator()
calls and use AnyGenerator
initializers instead. I have a fair number of these to update. Deprecated in 2.2, gone in Swift 3.Interactive playgrounds return in Xcode 7.3 Beta 2. These were a thing that got put aside when Apple integrated the iOS simulator into the playground assistant, and have finally re-emerged. Here’s an example in action. The following demonstration creates a view controller instance and ties a switch to a custom action callback.
Unfortunately, a lot of the tricks I used to do to create full-class OS X apps that supported drag and drop into playground windows are no longer working under the current system. I could, however, create a basic interactive NSView that properly handled mouse events:
I’m a little sad about the wider drag-and-drop utility for system interaction being lost. I’m hoping this returns in a later beta.
There’s a lot more to life than just simple for-in’s. Add flair to your code with these iteration power-ups.
A where
clause introduces simple predicate support during iteration. It tells Swift to skip any element that doesn’t fulfill the logic laid out in an associated requirement.
For example, you can iterate only over even cases:
for i in 1...10 where i % 2 == 0 { print("\(i) is even") }
Or you might pick out long words:
for word in ["Lorem", "ipsum", "dolor", "sit", "amet", "consectetur", "adipiscing", "elit"] where word.characters.count > 5 { print(word, "is a long word") }
You can complicate your requirements however you like, using complex conditions in your where clauses. This example prints even numbers between 21 and 29:
for i in 1...50 where i > 20 && i < 30 && (i % 2 == 0) { print("\(i) is even") }
Using where
enables iteration to pick and choose which items to process.
Optionals are the natural outcome of many Swift development scenarios, such as mapping a function over a collection or retrieving potentially failable assets.
You can combine Swift 2’s .Some
case shortcut with iteration to operate only on those items that aren’t nil
:
let items: [String?] = [nil, nil, "Hello", nil, "World"] for case let item? in items { print(item) }
The bound item is unwrapped within the for loop’s clause, so you can use it directly however you need.
Swift enables you to use conditional casting to filter lists of heterogenous objects to those that belong to a specific superclass. Here’s an example that extracts UIView
instances.
let mySwitch = UISwitch() let myView = UIView() let myDate = NSDate() let myItems: [NSObject] = [mySwitch, myDate, myView] for case let item as UIView in myItems { print(item.frame) }
This approach also works with protocols. Here’s a super-contrived case that demonstrates the approach:
protocol MyCustomProtocol { var frame: CGRect {get} } struct Bar {} struct Foo: MyCustomProtocol { let frame: CGRect = .zero } extension UIView: MyCustomProtocol {} let otherItems = [Bar(), Foo(), UIView()] as [Any] for case let item as MyCustomProtocol in otherItems { print(item.frame) }
for var
Although I did not use for var
in any of these examples but I thought I’d give you a heads up in this write-up that this mutable feature is on its way out of the Swift language. In Swift 2, the following code prints 4, 5, and 6.
for var x in 1...3 { x += 3 print(x) } // outputs 4, 5, 6
Swift 3 eliminates all for-var
constructs. Replace
for var x in 1...5 {...}
with
for x in 1...5 {var x = x; ...}
The same caution holds for for case var
and all other similar approaches.
Just submitted an updated version of Swift Documentation Markup to the iBooks and Leanpub stores. This new version includes revisions to my coverage of the excellent Jazzy documentation tool and new coverage of the VVDocumenter Xcode plugin, which automatically adds documentation templates to your code when you type ///.
Jazzy now supports some markup parsing, including parameters. Compare the output from the new version, shown here:
with the old output here:
It’s a fantastic and welcome improvement.
The VVDocumenter works by adding documentation templates to any symbol when you type /// (three forward slashes) before its declaration.
Just fill in the boilerplate with your details. VVDocumenter automatically adds placeholder tokens using <# and #> so they highlight in your source editor.
Note that as with any plug-in, you need to keep VVDocumenter up to date so it works with each revision and beta of Xcode.