The updates to LLVM packaged with Xcode 7.3 cause several new warnings. Most of them related to Swift, but there are also a few bugging us in legacy Objective-C code.
Xcode 7.3. updates Swift to 2.2. The warnings we are about to discuss are mostly deprecations which technically would still work, but will stop to work in Swift 3 which will be released “late 2016”. What’s particularly fascinating is that development of Swift is now driven by an open community process.
For the most part, Xcode provides perfect fix-its for the warnings. But let’s review them one by one as this might provide some enlightenment.
One of Swift’s design goals is to fit well into the family of C-languages. However some of the C-constructs were found to be confusing to newcomers or not providing any lasting benefits.
The first warning that catches our eye comes from a Swift Evolution proposal #4 by the LLVM master of ceremony himself, Mr. Chris Lattner. I love it to see that even Apple people are adhering to this new process of transparency.
The proposed fix-it replace i++ with i+=1. Same effect, it increments i by 1.
In this case the same line triggered a second fix-it as well, related to the C-style for loop.
The second proposed fix is more radical, it relates to the entire C-style for loop. This Swift Evolution proposal #7 comes from none other than famous Erica Sadun. Apparently, when not writing books, she proposes enhancements to Swift.
The proposal was much more controversial with several people raising concerns about the performance of replacing C-style for loops with Swift’s for-in. But in the end the proposal prevailed.
The resulting code is 5 characters shorter (because of the omitted var and the i++) and yet more elegant:
for var i=0; i<numberOfSlices; i++ // before for i in 0 ..< numberOfSlices // after
Don’t you love it?
New Selector Syntax
Objective-C allowed us to use any string as selector. That would give use great flexibility in messaging methods along the responder chain, but more often than not might lead to an unexcited “unrecognized selector” crash.
Few people actively use messaging the first responder (und subsequently the responder chain) on iOS, much less so than on OSX where you are almost forced to using it. For example if you have a menu item that is connected to the copy: selector the message would travel up the responder chain until it found a controller (view, window or document) that implements it.
Doug Gregor, working at Apple, drafted Swift Evolution proposal #22 which introduces the #selector syntax. This new syntax lets the compiler check for the existence of selectors at compile time.
Whereas you previously would only name the method name, you now have to reference the class containing the selector as well. This would have been the target-part of the target/action pattern we have previously used for buttons, gesture recognizers and notifications.
There are two drawbacks of this new syntax which are apparently considered to be less severe than unrecognized selector exceptions. For one, having the class as part of the selector duplicates the target: piece. And it might even contradict the class of the target, when the target is of an unrelated type.
In a recent Mac app I messaged the first responder by leaving the to-target nil. Now I needed to specify any class that would implement the selector:
NSApp.sendAction("reviewBundle:", to: nil, from: nil) // before NSApp.sendAction(#selector(OnlineTabViewController.reviewBundle(_:)), to: nil, from: nil) // after
Now imagine an expert in responder chains having several different classes which implement this reviewBundle: method. Which would you choose then for the #selector? The consensus seems to be that the cleanest approach would be to define a Swift protocol containing those methods and name this in the #selector.
This is one of few evolutionary changes to Swift which doesn’t decrease the number of characters you need to type to get the job done. But I guess it has some upsides and Xcode forces us to embrace it.
There are a few additional proposals which have been accepted for Swift 3, which already rear their heads via warnings and fix-its. The one that I bumped into was the one about removing the ability to tag function parameters with var or let. The latter is implicit, you cannot modify function parameter values inside the function. And making it modifiable with var serves no practical purpose because the scope of this variable is limited to the function anyway.
Another argument for this deprecation revolved around beginners being confused between var and inout. The latter will be moved to the right side of the colon in Swift 3.
Those were the Swift 2.2. changes which resulted in deprecation warnings. I also encountered one issue in particular – in legacy Objective-C code – which does not seem to be connected to Swift Evolution.
In Objective-C you often had the pattern that you would query a value which would write the value into a variable by reference. Now I found – on several occasions – that the compiler would now complain that I was using an uninitialized variable, even though I was doing so in a then-block of an if that would only be called in case of success of the query.
To work around this new bogus warning, I changed the logic such that it would always initialize the variable. This example is from DTCoreText where the effective range of glyphs is determined belonging to a single hyperlink. The warning was getting logged in the block at the end of this commit, even though linkURL had to be non-nil to get there.
It is very valuable to get informed when accessing non-initialized variables, but there are clearly some edge cases where the warning constitutes a false positive. But a few false positives are not a big deal if they prompt you to make your code easier to read for machine and humans alike.
On balance I am excited about the openness and involvement of people outside Apples inner circle that is the compiler team. Publicly inviting, discussing and implementing proposals for Swift’s betterment has yielded a few interesting improvements already.
For the most part – if you don’t have too much “clever” code you can get by with accepting all the fix-its attached to the deprecation warnings. Those warnings where this doesn’t work should prompt you to make your code more simple to reason about.
In the least we learn a great deal about the thought processes in Swift Evolution by reading the proposals and we get a nice preview of what will be in the future.
Also published on Medium.