Swift 4: Release Process and Phase 2

Release Process

The Swift 4 release process targets Fall 2017:

Swift 4 is a major release that is intended to be completed in the fall of 2017. It pivots around providing source stability for Swift 3 code while implementing essential feature work needed to achieve binary stability in the language. It will contain significant enhancements to the core language and Standard Library, especially in the generics system and a revamp of the String type. More details can be found on the Swift Evolution page.

Swift 4 Phase 2

The Swift 4 two-stage release plan was established in July 2016: focusing on essentials and ABI stability.  Swift  4 only focuses on Phase 1 at this time. Stage 2 starts now.

All design work and discussion for stage 2 extends to April 1, 2017. The intent is to timebox discussion to provide adequate time for the actual implementation of accepted proposals.

Deferred ABI and Status Updates

Ted Kremenek writes,

Since July, we now have a much better understanding now of how to achieve ABI stability, with an ABI Manifesto https://github.com/apple/swift/blob/master/docs/ABIStabilityManifesto.md detailing the list of all language/implementation work that is needed to achieve ABI stability. We have made substantial progress in that work during stage 1, but much remains to be done. Once Swift achieves ABI stability the ABI can be extended, but not changed. Thus the cost of locking down an ABI too early is quite high.

Deferring ABI stability enables Swift to focus on language fundamentals. An ABI dashboard will be wired up from the Swift Evolution Github repository. This will present a table of remaining ABI tasks and display their status.

Foundation

Swift Foundation API improvements are folded under the phase 2 umbrella, “to continue the goal of making the Cocoa SDK work seamlessly in Swift. Details on the specific goals will be provided as we get started on Swift 4 stage 2.”

Unimplemented Proposals

The following accepted proposals are rolled forward into Swift 4 Stage 2:

  • SE-0104 “Protocol-oriented Integers”: This proposal requires revision and another round of review based on other changes that have been made to the language and standard library since acceptance.
  • SE-0075 “Adding a Build Configuration Import Test”: This is (still) an additive proposal and no other changes affect this proposal. It will be carried forward and considered accepted for Swift 4.
  • SE-0042 “Flattening the function type of unapplied method references”: This proposal requires another round of review. This is a significant source-breaking change, and the bar for such source-breaking changes is considerably higher in Swift 4 than it was in Swift 3.
  • SE-0068 “Expanding Swift Self to class members and value types”: This is (still) an additive proposal and no other changes affect this proposal. It will be carried forward and considered accepted for Swift 4.

Links

That API thing

Today, Nikita Voloboev was trying to wrap his head around how this whole Cocoa/Cocoa Touch API thing worked. The conversation started when he asked, “Is UIKit part of Cocoa?” The docs weren’t really giving him an idea of how it all worked. After a few minutes back and forth, he derived this concept using the tools at mindnode.com:

It was a good first guesstimate even though it doesn’t exactly capture Apple’s API design. I hopped into Preview and sketched out this diagram instead. (And yes, some day I may write a book about all the cool things you can do for free in Preview):

I explained how the API families shared certain frameworks but that the frameworks weren’t uniformly implemented across all the platforms within that family. Cocoa and Cocoa Touch, I tried to explain, were the API families specific to four operating systems: macOS, iOS, watchOS, and tvOS.

I pointed him to this definition, which I pulled up by a web search for define cocoa apple:

Cocoa is Apple’s native object-oriented application programming interface (API) for their operating system macOS. For iOS, tvOS, and watchOS, a similar API exists, named Cocoa Touch, which includes gesture recognition, animation, and a different set of graphical control elements.

He then threw that definition into another mind map, which he uses to keep notes. This was a cool and unexpected way of exploring new knowledge:

 

I’m fascinated by his learning toolset, which includes both mind mapping and Anki Decks (see https://apps.ankiweb.net and this explanation of Spaced repetition.) I tend to turn to paper and pen, or other familiar tools, to take notes or to share.

What kind of tools do you use to explore and explain new areas of learning?

Swift Style: Now Available for Amazon Pre-Order

Swift Style is almost wrapped up. I’m just waiting for some final copy edits. Notably, pre-orders are live on Amazon. (You can ignore the dates, page counts, etc there. They’re just place-fillers.) I just did a product video for Amazon, which hopefully will be posted over the next few weeks.

Once printed, Style will be on sale at all the major retailers as well as at Pragmatic. Pragmatic gives you the option of hybrid ebook/printed bundles, and gives me a slightly better slice of the royalty pie, if that matters to you. It’s a nice thing for me.

I’ll be remote talking about the book and Swift Style at PlaygroundsCon on the 24th (the 23rd in the US) this month and Forward Swift 2 on March 2. I also recently gave a talk at Realm’s Swift user SLUG meetup, which you can watch by following the link earlier in this sentence.

That’s not to say this project is done. Swift Style evolved from talking to developers. It represents viewpoints from the larger Swift development community. That process can and will continue as people read the book and I expand its guidance. The people at Pragmatic have been lovely in helping me plan out the book’s future as well as its present.

Challenge: Filtering associated value enumeration arrays

The Challenge

Courtesy of Mike Ash, here’s the challenge. You have an enumeration:

enum Enum {
    case foo(Int)
    case bar(String)
    case qux(Int)
}

And you have an array of them:

let items: [Enum] = [.foo(1), .bar("hi"), .foo(2)]

Return a filtered array containing only one case, for example foo. The difficulty lies in that Swift does not seem to offer a == or ~= operator that works on cases, ignoring associated values:

// does not work
let filtered = items.filter({ $0 == .foo })

So what do you do?

Attempt 1

Here’s my first attempt. Super ugly but it gets the job done:

let filtered = items.filter({ 
    switch $0 { case .foo: return true; default: return false } })

Evan Dekhayser prefers if-case:

let filtered = items.filter({ 
    if case .foo = $0 { return true }; return false })

And you can of course use guard as well:

let filteredy = items.filter({ 
    guard case .foo = $0 else { return false }; return true })

Attempt 2

Just as ugly but slightly shorter in terms of number of characters. But it does more work than #1:

let filtered = items.filter({ 
    for case .foo in [$0] { return true }; return false })

Again, yuck.

Attempt 3

I really hate this approach because you have to implement a separate property for each case. Double yuck:

extension Enum {
    var isFoo: Bool {
        switch self { case .foo: return true; default: return false }
    }
}
let filtered = items.filter({ $0.isFoo })

Attempt 4

This is gross because it requires a placeholder value for the rhs, even though that value is never used. And no, you can’t pass an underscore here:

extension Enum {
    static func ~= (lhs: Enum, rhs: Enum) -> Bool {
        let lhsCase = Array(Mirror(reflecting: lhs).children)
        let rhsCase = Array(Mirror(reflecting: rhs).children)
        return lhsCase[0].0 == rhsCase[0].0
    }
}
let filtered = items.filter({ $0 ~= .foo(0) })

Attempt 5

Then I got the idea into my head that you could use reflection. If you don’t supply a value to an enumeration case with an associated value, it returns a function along the lines of (T) -> Enum. Here is as far as I got before I realized the enumeration *name* was not preserved in its reflection:

import Foundation

extension Enum {
    var caseName: String {
        return "\(Array(Mirror(reflecting: self).children)[0].0!)"
    }
    
    static func ~= <T>(lhs: Enum, rhs: (T) -> Enum) -> Bool {
        let lhsCase = lhs.caseName
        let prefixString = "Mirror for (\(T.self)) -> "
        let typeOffset = prefixString.characters.count
        let typeString = "\(Mirror(reflecting: rhs).description)"
        let rhsCase = typeString.substring(from: typeString.index(typeString.startIndex, offsetBy: typeOffset))
        return true
    }
}

Yeah. Really bad, plus it doesn’t work.

Call for solutions

Since I didn’t really get very far with this, I’m throwing this out there as an open challenge. Can you come up with a parsimonious, readable, and less horrible (I was going to say “more elegant”, but c’mon) way to approach this? I suspect my first attempt may be the best one, which would make me sad.

Non-contiguous raw value enumerations

Brennan Stehling recently uncovered a fantastic Swift feature I was completely unaware of. I knew you could create raw value enumerations that automatically incremented the value for each case:

enum MyEnumeration: Int {
   case one = 1, two, three, four
}

MyEnumeration.three.rawValue // 3

And I knew you could create raw value enumerations with hand-set values:

enum MyEnumeration: Int {
    case one = 1, three = 3, five = 5
}

But I didn’t know that you could mix and match the two in the same declaration! (Although, you probably shouldn’t do this for standards-based values like the following example…)

enum HTTPStatusCode: Int {
    // 100 Informational
    case continue = 100
    case switchingProtocols
    case processing
    // 200 Success
    case OK = 200
    case created
    case accepted
    case nonAuthoritativeInformation
}

HTTPStatusCode.accepted.rawValue // 202

How cool is that?

I’d probably reserve this approach for values with offsets (for example, “start at 1”), and where the underlying values don’t have established semantics. As Kristina Thai points out, skipping meaningful values doesn’t help readability or inspection.

Overdrive, DRM, and Adobe Digital Editions

The Denver library recently migrated its ebook system. Incidentally, it wiped all my holds in the process and I have no idea what stuff I was waiting to read. So if you recced anything over the past 6 months and it was popular, chances are that I need you to remind me to read it again.

Anyway, today my first hold came in on the new system. I downloaded the ascm file as usual, double clicked, and when Adobe Digital Editions opened, I got this on my screen:

Yikes. I immediately assumed it was time to update Adobe Digital Editions. So I did that. And I tried opening it up again and I got this:

While you can see the massive UI improvements Adobe has made to its signature Mac e-reader, I was still rather stuck.

So I googled for E_ACT_NOT_READY and “IO Error on Network Request” and tried all the things that didn’t work until I found something that did work.

What didn’t work:

  • Clearing out ~/Documents/Digital Editions
  • Creating a new ~/Documents/My Digital Editions
  • Quitting and restarting the apps
  • Rebooting

What did work was reauthorizing my computer. Dunno why. I deauthorized and then reauthorized — good thing I remembered my username and password because it has been a gadzillion years since I did this last — and boom it finally worked.

(If you want to remove authorization by hand, toddle over to ~/Library/Application Support/Adobe/Digital Editions and kill the activation.dat file.)

Anyway, Scott Sigler’s “Alive” is now on my system ready for reading. I have no idea why I put this title on hold and who recommended it to me. I hope it’s good. Here’s finger’s crossed that this is a good read.

Pretty much every way to assign optionals

Store a non-optional or an optional to an optional

The basics. This isn’t rocket science:

optItem = 5 // optItem is now .some(5)
optItem = optValue // optItem is whatever optValue is

Summary

How often do you do this? All the time

How ridiculous is this approach? Not at all

Store an optional to a non-optional

Many functions and methods that return optional values. When you use try? with throwing, that returns optional values too.  You often need to store those results to a non-optional variable or property.

To do this, you test for nil and then store an unwrapped version of any non-nil results. Here are a few approaches.

Conditional Binding

Use if let to conditionally bind the optional and then perform the assignment:

if let optItem = optItem { 
    item = optItem // if optItem is non-nil
}

You can also use if case if you really want to although these do exactly the same things as if let:

// Sugared optional
if case let optItem? = optItem { 
    item = optItem // if optItem is non-nil
}

// External let
if case let .some(optItem) = optItem {
    item = optItem // if optItem is non-nil
}

// Internal let
if case .some(let optItem) = optItem { 
    item = optItem // if optItem is non-nil 
}

Nil Coalescing

You can use nil coalescing to provide a fallback value:

item = optItem ?? fallbackValue

If you don’t want a fallback value, you can use the item’s original value:

item = optItem ?? item

A slight caution. I don’t know if the compiler optimizes away the “assign self to self” case. If it has to do both the check and assignment,  this may be less efficient than the if let approach.

Also, I’m not giving this high marks for efficiency or readability because I think it’s worth the extra if let words to make clear the intent that you only update item if optItem is non-nil

Summary

How often do you do this? Often

How ridiculous is this approach? Not at all

Update optional only if optItem is non-nil

This variation describes a scenario where you skip updates when an existing optional is nil. In this case, nil means “don’t touch this optional”. I can count up to zero the number of times this scenario has ever arisen for me.

The obvious solution:

if optItem != nil { optItem = newValue }

The extremely weird solution using a ? marker:

optItem? = nonOptionalValue

In this use of ?, the rhs must be a non-optional, guaranteed at compile time. This is a pretty obscure Swift language feature. (Thanks to Joe Groff for reminding me it existed.)

Or you could do this (which is kind of silly) for “test for non-nil receiver” assignment:

if let optValue = optValue {
    optItem? = optValue
}

In this example, the rhs of the ?-powered assignment has to be non-optional. Conditionally binding the optional enables you to use it with ?. Madalin Sava offers the following simple alternative. It gets high marks for parsimony, low marks (as everything in this section does) for non-obvious outcomes:

optItem? = optValue ?? optItem!

 

Summary

How often do you do this? Never

How ridiculous is this approach? Extremely

Update optional only if optItem is nil

This variation can best be described as “set once, use mostly”. Once assigned to a non-nil value, the optional should never be overwritten. The simplest approach is to check for nil before assignment:

if optItem == nil { optItem = newValue }

Or burn an operator, which you probably won’t want to do:

infix operator =?? : AssignmentPrecedence

// "fill the nil" operator
public func =??<T>(target: inout T?, newValue: T?) {
    if target == nil { target = newValue }
}
optItem =?? newValue

See also: SE-0024

Summary

How often do you do this? I don’t do this but I can see the utility when hooking up assets that you don’t want to overwrite. This is kind of a mad-world version of implicitly unwrapped optionals but one where you test to ensure you’ll never change them again, not one (as with IUO’s) where every successive change has to be a non-nil value.

How ridiculous is this approach? Not ridiculous but also not common.

Update optional only if new value is non-nil

This scenario basically mimics implicitly unwrapped optionals but with added safety and no IUO crashing. You always test for non-nil so once set to a valid value the optional will never return to nil.

Limit updates to non-nil new values and discard nil assignments:

if let newValue = newValue { optItem = newValue }

Or this (which feels wasteful as it performs a re-assignment for nil-values, doesn’t it?):

optItem = newValue ?? optItem

or burn an operator, which again you probably won’t want to do:

infix operator =? : AssignmentPrecedence

// "assign non-nil values" operator
public func =?<T>(target: inout T, newValue: T?) {
    if let newValue = newValue {
        target = unwrapped
    }
}

See also: Swift Evolution.

Summary

How often do you do this? I don’t but I can see how people might want to use this with non-IUO optionals.

How ridiculous is this approach? Not ridiculous but also not common.


I’m sure I’ve gotten some of this write-upwrong. Tell me and I’ll fix.

Why we develop

From my inbox:

I have been steadily using folderol in order to help me define which folders are important, as well as which ones are not.

Folderol has also been handy to me in developing subfolders within folders and having those subfolders be different colors, which helps me find the information inside of them quicker.

Thank you for developing such a great product.  If the folderol app is any indication of other products that you might have developed or that are in the development stage, I look forward to seeing what other applications you have.

Respectfully,

Demetrius Moyston

Folderol at the Mac App Store