Archive for August, 2016

More fun with sequences!

I want to share a little conversation from Swift-Users. KS Sreeram wrote:

I’m trying to initialize a byte-array efficiently with minimal copying with the following steps:

1. Create an empty byte array.
2. Reserve sufficient capacity in the array.
3. Use mutable pointers into the array to fill in the data.
4. The actual size that was filled is known only after it is filled in.
5. I would like to set the size of the array to the actual size.

I couldn’t find any methods for doing the last step. Is there a way to do this?

Dave Abrahams’ response:

Create a Sequence that represents the elements you’re going to append, e.g.:

 var a = [1, 2]
 a.reserve(256)
 a += sequence(first: 3, next: {$0 < 1000 ? ($0 + 3) * 2 : nil})

There are lots of ways to make Sequences, but the overloaded sequence() functions are probably the easiest.

Sadly:

Dear Erica: Taking the NS off

Dear Erica, Where can you find a list of all the Foundation classes losing the NS prefix? Will any UI ones do the same? — Seivan

The whole “NS prefix stripping” initiative is part of Tony Parker and Philippe Hausler’s SE-0086, which you’ll find by following the link to the proposal. It contains a list of the classes affected by SE-0086’s adoption.

The reasoning behind this proposal goes like this: Swift has a compelling interest in creating a core library suite to support common Swift design patterns. This interest in unifying a core library extends to platforms that lack historic ties to NeXTStep.

To provide this universal support, the Swift Programming Language requires the creation of a family of libraries that will ship with the compiler. This core functionality extends beyond the existing Swift Standard Library and is tentatively called the Swift Core Libraries.

Key elements that will be developed for the library include dispatch, internationalization/localization, and unit testing. As these libraries are both fundamental and native to the Swift language, their naming style needs to be “Swifty”. This renaming differentiates them from Cocoa Foundation:

In addition to adopting the guidelines for method names, the names of the fundamental types should follow the spirit of the guidelines too. The type names should be clear, concise, and omit needless words or prefixes. In combination with adopting Swift semantics for many of these types (SE-0069), and continued improvement to the implementations, this will make core library API feel like it belongs to the Swift language instead of like a foreign invader.

To answer your question, classes tied specifically to Objective-C and the Objective-C runtime, as well as those that are Apple platform specific (AppKit and, as you asked, UIKit) will retain their NS (or UI) prefix. Those that are more universally applicable will slowly lose that prefix through a series of upgrades and redesigns, especially as the tension between Swift value type and Foundation reference type implementations are better explored.

SE-0086 has been through a significant revision. Numerous classes  included in the original write-up were later removed:

Screen Shot 2016-08-09 at 8.50.31 AM

The authors wrote,

 We considered simply dropping the prefix from all types. However, this would cause quite a few conflicts with standard library types. Also, although Foundation’s framework boundary is an easy place to programmatically draw the line for the drop-prefix behavior, the reality is that Foundation has API that feels like it belongs to higher level frameworks as well. We believe this approach better identifies the best candidates for dropping the prefix.

Because of this revision, fairly universal items like attributed strings, time zones, tasks, and sort descriptors did not make it through the first round of renames but may be considered again as the Swift language evolves.

SE-0086 and its heirs will not be taking up the case of renaming the core UI elements that are so tied to Apple’s platforms and their look and feel. That said, I would love to see a push to expand the Swift language to include more constructed literals, and here is my reasoning why.

A constructed literal expresses concepts that are inherently cross-platform. Swift’s constructed literal set currently includes colors, paths, and images. Colors and images fall under the platform-specific umbrella that excludes them from being part of the core library system.

Using a constructed literal allows these platform-tied elements to participate in the core Swift language because implementation details are left to the destination platform. You don’t have to work whether an item is a UIColor, an NSColor, an SKColor, or a CIColor because a color literal builds on an underlying commonality that colors can be expressed using RGBA notation.

Extending the constructed literal set from colors, paths, and images to  views, fonts, and more provides an interesting way to move forward. Like colors and images, these platform types are essentially universal concepts. They could defer of implementation details to destination platforms, allowing them to be created in core Swift.

While I’d love to see this discussed, it’s pretty clear that this kind of additive proposal will probably be deferred to at least Swift 5, as Swift 4 focuses on a much more narrow set of goals.

Questions: “Can you call super in a setter?”

k writes: “Can you call super in a setter? e.g. override a setter and call super with a different value?”

Sure. Here’s an example:

class Foo {
    var value: String
    init(value: String) { self.value = value }
}

class SubFoo: Foo {
    override var value: String {
        get { return super.value }
        set { super.value = newValue.lowercased()
        }
    }
}

The SubFoo class works like Foo but lowercases its value on assignment (although not, in this implementation, on initialization). So if you create an instance of the subclass and assign a mixed-case string, the assignment automatically lowercases it and then applies the superclass’s assignment.

let a = Foo(value: "Hello World")
let b = SubFoo(value: "Hello World")
debugPrint(a.value, b.value) // "Hello World", "Hello World"
b.value = "Hello Sailor"
debugPrint(a.value, b.value) // "Hello World", "hello sailor"

I’m not sure if there’s a ton of useful cases for this but it is certainly possible.

Cleaning up single if-case use

There’s a pattern I find myself using that I’m trying to train myself out of and it goes something like this:

switch something {
    case some complicated binding case: 
        // ...do stuff with the binding results
    default: break
}

Here’s a real-world example:

enum Tree<T> {
    case empty
    indirect case node(value: T, left: Tree<T>, right: Tree<T>)
 
    func show(indent: Int = 0) {
        switch self {
        case let .node(value: value, left: left, right: right):
            print(String(repeating: " " as Character, count: indent), value)
            right.show(indent: indent + 4)
            left.show(indent: indent + 4)
        default: break
        }
    }
}

The reason I’m trying to break myself out of this pattern is that there’s a much simpler way to do this, which is to use if case instead of switch. There’s only one case to consider, and the default case does nothing.

Refactoring produces the following simplified code, allowing all the binding and the behavior related to the .node case to be compressed together.

enum Tree<T> {
    case empty
    indirect case node(value: T, left: Tree<T>, right: Tree<T>)
 
    func show(indent: Int = 0) {
        if case let .node(value: v, left: l, right: r) = self {
            print(String(repeating: " " as Character, count: indent), v)
            r.show(indent: indent + 4)
            l.show(indent: indent + 4)
         }
}

I tend to push myself to use switch and guard over if for many cases to enhance intent and readability, but this is one example where it’s really best just to stick with the classics.

iOS Playgrounds: Where is my print output?

Nate writes: “I can’t figure out how to show console output/print in the Swift Playgrounds app for iOS.”

All print output appears in the “sidebar” to the right of the code as little pop-ups:

Screen Shot 2016-06-22 at 1.11.56 PM

Embed the viewer by tapping “Add viewer” so you don’t have to keep popping up the quick view.

The hint box shown (for example “123”, or “?”, or “abc”, etc) depends on the type of item produced. The tiny cube represents an class instance.

Screen Shot 2016-06-27 at 11.40.51 AM

Like desktop playgrounds, you can view a single value at a time or tap the embedded display to select other views like List view:

Screen Shot 2016-06-24 at 12.15.27 PM

Compilation errors appear in-line for main playground code:

https://i2.wp.com/ericasadun.com/wp-content/uploads/2016/06/Screen-Shot-2016-06-21-at-11.51.25-AM.png?resize=859%2C690&ssl=1

Sources-based errors (which  you cannot yet fix in the app) are shown as popups. When these issues occur, debug back on  your Mac before trying again on iOS.

https://i1.wp.com/ericasadun.com/wp-content/uploads/2016/06/Screen-Shot-2016-06-21-at-11.29.05-AM.png?resize=859%2C690&ssl=1

It’s important to remember that the iOS Playgrounds app almost never is running the same version of Swift as you are on the desktop and won’t be until both Swift 3 and iOS 10 go gold.

Want to learn more about iOS Playgrounds? Read Playground Secrets and Power Tips.

Idiomatic Swift: conditional unwrapping initialization

Over on Swift-Users, Dan T asks:

Currently I do stuff like this:

let dobString: String
if let dob = dob {
    dobString = serverDateFormatter.stringFromDate(dob)
}
else {
    dobString = ""
}

Is there a better, more idiomatic, way to do this sort of thing?

I’m going to assume that serverDateFormatter is an instance of NSDateFormatter. If so, what Dan’s going for might be better expressed like this :

let dobString: String = {
    guard let dob = dob else { return "" }
    return serverDateFormatter.string(from: dob)
}()

I think it’s a lot cleaner, and it only mentions dobString once. (If he’s not using NSDateFormatter and needs a second level of unwrapping, the guard let statement just needs a second clause that performs a conditional binding on the results of stringFromDate.)

Update: Tim Vermeulen has a much nicer one-line solution.

let dobString = dob.flatMap(serverDateFormatter.stringFromDate) ?? ""

I’m pretty sure that this can use map as well as flatMap, which saves you four more characters.

Got a better solution? Toss it into the comments, tweet it, or hop onto the Swift-Users email list.

Messing with Extensions: Describing color literals for the color blind

As the latest nightly build of Swift refuses to link on my system, I put together a new source editor extension. Developing these is still about as fun as having wisdom teeth pulled (actually the dental surgery would be more fun) but I’ve learned to keep a terminal window open so I can repeatedly delete derived data between builds:

Screen Shot 2016-08-03 at 11.41.33 AM

The new extension looks for a color literal on the cursor line and uses the XKCD color library to describe it.

Geomapping the Swift Change Log

I’m having the worst time trying to get newer Swift snapshots to compile and link code — let alone getting Swift built by hand:

Screen Shot 2016-08-01 at 9.30.11 AM

Unfortunately, the Swift change log, which goes in reverse chronological order is slightly messed up. I can’t find a single canonical Beta 3 cutoff where everything before that point is implemented, and after is pending.

SE-0099, which separates conditional clauses with commas while eliminating where from associated boolean conditions is implemented.

if let x = x where x % 2 == 1 { ... } // does not compile
if let x = x, x % 2 == 1 { ... } // compiles

SE-0060 is up and running too, ensuring that default arguments are specified in declaration order.

func foo(a: Int = 2, b: Int = 2, c: Int = 2) {}
foo(a: 1, c: 2) // compiles
foo(c: 1, a: 2) // error: argument 'a' must precede argument 'c'

However, SE-0112, which appears after (“earlier”) than SE-0099 is not.

// SE-0112
let cocoaError = NSError(domain: "org.sadun", code: 42, userInfo: [:])
do {
    throw cocoaError
} catch {
    print(error.code) // bzzt, won't compile
}

Yet SE-0081 (move where clauses to the end of declarations) is working fine.

public func ==== <S1: Sequence, S2: Sequence>(seq1: S1, seq2: S2) -> Bool 
    where
    S1.Iterator.Element == S2.Iterator.Element,
    S1.Iterator.Element: Equatable
{
    return !longZip(seq1, seq2).contains(!=)
}

Right now, I’m hoping hard that Beta 4 will get us super-close to a full “Swift 3”