Archive for the ‘Swift’ Category

A different way to develop SwiftPM Packages inside Xcode projects

WWDC gave us many reasons to both migrate libraries to SwiftPM and to develop new ones to support our work. The integration between Xcode development and SwiftPM dependencies keeps growing stronger and more important.

Apple’s Editing a Package Dependency as a Local Package assumes you’ll drag in your package to an Xcode project as a local package overrides one that’s imported through a normal package dependency.

In Developing a Swift Package in Tandem with an App, Apple writes, “To develop a Swift package in tandem with an app, you can leverage the behavior whereby a local package overrides a package dependency with the same name…if you release a new version of your Swift package or want to stop using the local package, remove it from the project to use the package dependency again.”

I don’t use this approach. It’s not bad or wrong, it just doesn’t fit my style.

On the other hand, opening the Package.swift file directly to develop has drawbacks in that it doesn’t fully offer Xcode’s suite of IDE support features yet.

So I’ve been working on a personal solution that best works for me. I want my package development and its tests to live separately from any specific client app outside a testbed. I need to ensure that my code will swift build and swift test properly but I also want to use Xcode’s built-in compilation and unit testing with my happy green checks.

I set out to figure out how best, at least for me, to develop Swift packages under the xcodeproj umbrella.

I first explored  swift package generate-xcodeproj. This builds an Xcode library project complete with tests and a package target. You can use the --type flag to set the package to executable, system-module, or manifest instead of the default (library) during swift package init:

Generate% swift package init
Creating library package: Generate
Creating Package.swift
Creating README.md
Creating .gitignore
Creating Sources/
Creating Sources/Generate/Generate.swift
Creating Tests/
Creating Tests/LinuxMain.swift
Creating Tests/GenerateTests/
Creating Tests/GenerateTests/GenerateTests.swift
Creating Tests/GenerateTests/XCTestManifests.swift
Generate% swift package generate-xcodeproj
generated: ./Generate.xcodeproj

Although SwiftPM creates a .gitignore file for you as you see, it does not initialize a git repository. Also, I always end up deleting the .gitignore as I use a customized global ignore file. This is what the resulting project looks like:

As you see, the generated Xcode project has everything but a testbed for you. I really like having an on-hand testbed, whether a simple SwiftUI app or a command line utility to play with ideas. I looked into using a playground but let’s face it: too slow, too glitchy, too unreliable.

It’s a pain to add a testbed to this set-up, so I came up with a different way to build my base package environment. It’s hacky but I much prefer the outcome. Instead of generating the project, I start with a testbed project and then create my package. This approach naturally packs a sample with the package but none of that sample leaks into the package itself:

I end up with three targets: the sample app, a library built from my Sources, and my tests. The library folder you see here contains only an Info.plist and a bridging header. It otherwise builds from whatever Sources I’ve added.

I much prefer this set-up to the generate-xcodeproj approach, although it takes slightly longer to set-up. The reason for this is that SwiftPM and Xcode use different philosophies for how a project folder is structured. SwiftPM has its Sources and Tests. Xcode uses a source folder named after the project.

So I remove that folder, add a Sources group to the project, and ensure that my build phases sees and compiles those files. The Tests need similar tweaks, plus I have to add a symbolic link from Xcode’s tests name (e.g. “ProjectNameTests”) to my SwiftPM Tests folder at the top level of my project to get it to all hang together. Once I’ve done so my green checks are ready and waiting just as if I had opened the Package.swift file directly. But this time, I have all the right tools at hand.

Since I’m talking about set-up, let me add that my tasks also include setting up the README, adding a license and creating the initial change log. These are SwiftPM setup tasks that swift package init doesn’t cover the way I like. I trash .gitignore but since I have Xcode set-up to automatically initialize version control, I don’t have to git init by hand.

I suspect this is a short-term workaround as I expect the integration of SwiftPM and Xcode to continue growing over the next couple of years. Since WWDC, I’ve been particularly excited about developing, deploying, and integrating SwiftPM packages. I thought I’d share this in case it might help others. Let me know.

The (Switch) Case of the Missing Binding

Here’s a cool little challenge brought up this morning by a friend. Consider the following code:

switch foo {
  case .a: return "a"
  case .b(let str) where str.hasPrefix("c"), .c: return "c"
  case .b: return "b"
}

It won’t compile.

When you bind a symbol for one pattern, you must bind that symbol for every pattern in a case. This prevents you, for example, from binding str in one pattern and then attempting to use str in the shared case body. For example, consider this case. What would you expect to happen when foo is .c?

func switchTheFallthroughOrder(foo: Foo) -> String {
    switch foo {
    case .a: return "a"
    case .b(let str) where str.hasPrefix("c"), .c:
        // Using `str` here is bad!
        print(str)
        return "c"
    case .b: return "b"
    }
}

Despite my first knee-jerk refactoring, moving out the .c case to use fallthrough doesn’t work. Again, this is because str is not bound for .c and could be used in the successive case body:

However, as Greg Titus pointed out, if you switch the order to use the binding case first with fallthrough, Swift knows at compile time that the binding won’t carry on beyond that scope. This resolves the error, since str is only used in the where clause to narrow the pattern matching:

Further, when using bindings in case tests, a waterfall approach where the bound items are used before fallthrough can extend through multiple steps with the blessing of the compiler:

case .widest(let first, let second) where first.satisfiesACondition():
    // can use `first`, `second` here
    fallthrough
case .medium(let second) where second.satisfiesAnotherCondition():
    // can use `second` here even if it was bound 
    // via `widest` above via fallthrough
    fallthrough
case .narrowest: return someValue

My thanks to Greg Titus for figuring this all out!

Importing Web-based SwiftPM packages to your Xcode Playground

I’ve been kicking the wheels on Xcode 12 and its ability to use frameworks and packages with playgrounds. Up until now, I’ve only been able to import packages that are either downloaded or developed locally on my home system. However, a lot of the packages I want to work with are hosted from GitHub.

I decided to follow a hunch and see if I could import my dependency through a local Forwarding package and then use that code. Long story short: I could.

Here’s my playground, successfully running.

The RuntimeImplementation is declared in a GitHub-hosted package called Swift-General-Utility:

What I did to make this work was that I created what I called a Forwarding Utility, whose sole job is to create a shell package that depends on the remote package and forwards it to the playground. It looks like this. It is a single file called “Forwarding.swift” (no, the name is not at all magic.) in Sources/. I use @_exported to forward the import.

/*
 
 Use this to forward web-based dependencies to Swift Pkg
 
 */

@_exported import GeneralUtility

Its Package.swift installs the dependency:

    dependencies: [ .package(url: "https://github.com/erica/Swift-General-Utility", .exact("0.0.4")), ],
    targets: [
        .target(
            name: "ForwardingUtility",
            dependencies: [ .product(name: "GeneralUtility"), ],
            path: "Sources/"
        ),
    ],

And that’s pretty much all that there is to it, other than (as I mentioned in my other post about how to use SwiftPM packages in playground workspaces) that you may have to quit and re-open the first beta before you can import the forwarding.

Let me know anything that I messed up. But also let me know if this was helpful to you!

“mint” (a simple SwiftPM installer) has improved my command line life

SwiftPM’s lack of an easy install feature has long been an issue of mine and for other people too. As the linked forums thread suggests, to accomplish this for a general audience requires some careful thinking: adding to /usr/local/bin is not always the best solution for every user.

Still, it’s a feature whose absence is notable. To fill the gap, I’ve discovered Yonas Kolb’s mint. Thank you to Leo Dion, who introduced this to me. It is ridiculously simple to use. Could it get easier than mint install erica/now? Admittedly my github id is short and so is my project name, but I think my point stands…

Yesterday, I hastily added a SwiftPM project to remind so it too could be installed via mint. Suddenly, adding the project specification is no longer an afterthought but a driving feature. It’s made SwiftPM support far more valuable to me for executables.

Make sure you name your primary file main.swift, your product to .executable, and if you’re developing in Xcode, override your path to point to the Xcode-project-style folder for the source files, usually the same name as the project itself. I mention this because Xcode by default (File > New > Swift Package) builds library projects, not executable ones. At the command-line use swift package init --type executable.

// swift-tools-version:5.2
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
    name: "remind",
    platforms: [
        .macOS(.v10_12)
    ],
    products: [
        .executable(
            name: "remind",
            targets: ["remind"]),
    ],
    dependencies: [
        .package(url: "https://github.com/apple/swift-argument-parser", from: "0.0.6"),
    ],
    targets: [
        .target(
            name: "remind",
            dependencies: [.product(name: "ArgumentParser", package: "swift-argument-parser")],
            path: "remind/"
        ),
    ],
    swiftLanguageVersions: [
        .v5
    ]
)

As for mint itself, you can build it or install it via HomeBrew: brew install mint.

If you have any suggestions on how I can improve my SwiftPM work, better integrate tagging, or any other tips, please let me know. Thanks!

Musings on `Result` and building a command line utility with completion handlers

Collaborating with Paul Hudson is a pleasure but the time difference can be, well, confusing. So when I started putting together an outline about the new command line argument parser for Pragmatic, one of the first things I wrote was a command line utility to tell me what time it was in Bath, UK:

% now bath uk
Bath 4:16:42 PM (GMT+1 United Kingdom Time)

I use CLGeocoder to use whatever terms I enter after the command as the hints to look up places of interests. I grab the first match and pull the time zone from that match (or throw an error if there’s no possible match).

Command-line utilities are not particularly well known for their asynchronous feature support. Because geocodeAddressString does run asynchronously, I use the quick and dirty trick of starting a runloop that executes until the completion handler finishes. I’m basically adapting an async method to sync.

This gave me an opportunity to finally get around to using the new Result type. Restrictions on other projects prevented me from kicking its wheels (or I was already using my own version from way back).

I struggled a little with how to incorporate Result. Here’s an earlier go at this. I use an optional resultto store the result, which is then set in completion scope:

var result: Result<[CLPlacemark], Error>?

CLGeocoder().geocodeAddressString(hint) { placemarks, error in
    switch (placemarks, error) {
    case (_, let error?):
        result = .failure(error)
    case (let placemarks?, _):
        result = .success(placemarks)
    default:
        fatalError("Geocoder error, no results.")
    }
    CFRunLoopStop(CFRunLoopGetCurrent())
}
CFRunLoopRun()

This code bothered me, and not just because I had to test and unwrap result when control returned to the main part of my method. It seems so obvious that Result should have a simple initializer based on the common elements found in legacy completion handlers. This would collapse those arguments to, for example, completion(Result(error, data)). Unless I’m missing something big here, I thought to build my own convenience initializer:

extension Result {
    init(_ success: Success?, _ failure: Failure?) {
        precondition(!(success == nil && failure == nil))
        switch (success, failure) {
        case (let success?, _):
            self = .success(success)
        case (_, .let failure?):
            self = .failure(failure)
        default:
            fatalError("Cannot initialize `Result` without success or failure")
        }
    }
}

That extension allowed me to collapse the code down to this. Notice how I can use the initializer here to eliminate the optional result, simplifying my extraction with get, towards the end. Admittedly, it’s not always easy to come up with an initial value that can be overwritten this way, but here it worked. The handler became two lines long, and processing the result to get my placemark (including all error handling), another two lines:

static func fetchPlaceMark(from hint: String) throws -> CLPlacemark {
    var result: Result<[CLPlacemark], Error> = Result([], nil)

    CLGeocoder().geocodeAddressString(hint) { placemarks, error in
        result = Result(placemarks, error)
        CFRunLoopStop(CFRunLoopGetCurrent())
    }
    CFRunLoopRun()

    let placemarks = try result.get()
    return placemarks[0]
}

I quite like my initializer and wonder why something like that doesn’t already exist unlike init(catching:() -> Success). I’m curious as surely I’ve missed something important. Even in normal completion handlers, I’d imagine using the legacy Error? and Data? optionals would be a common use-case for Result

Let me know.

Circles within circles: custom types and extensions

So the other day Paul and I were shooting the breeze about spirographs. He was saying I needed to get back to blogging now that I have the time. Of course, the second you set out to try to write a post, so many ideas flow forth at once, it actually is hard to pick just one and focus on it. Since he had enjoyed my drawing work, I thought I’d start out with a little push at circles.

That quickly went out of control because I ended up with enough material for a few chapters rather than a single blog post. (And, no, my chapter for his book is about property wrappers, which I love, rather than drawing)

To give a little context, before I decided to try my hand at full time work, I had had a contract with Pragmatic to update my Drawing book. I had to cancel that because commuting full time to another city left me with zero free time for my self, my family, let alone writing. (Now that I am back at my own desk, I may see about returning to that project because geometry is a core passion.)

Anyway, let me start at the end of all this and show you some pictures and then I’ll (pardon me) circle back and start telling the story of the code and how all this came to pass.

I started my day by opening a playground, deciding to just flex my coding and see where it would take me. I wanted to work with circles, so I plugged a range into a map to get me there.

// Get some points around a circle
let points = (0 ..< nPoints).map({ idx -> CGPoint in
  let theta = CGFloat(idx) * (CGFloat.pi * 2 / CGFloat(nPoints))
  return CGPoint(x: r * cos(theta), y: r * sin(theta))
})

// Create a path
let path = UIBezierPath()

// Get the last point before the circle starts again
let lastIndex = points.index(before: points.endIndex)

// Draw something interesting
for (point, index) in zip(points, points.indices) {
  let p0 =  index == lastIndex
    ? points.startIndex
    : points.index(after: index)
  let p1 = index == points.startIndex
    ? lastIndex
    : points.index(before: index)
  path.move(to: .zero)
  path.addCurve(to: point, controlPoint1: points[p0], controlPoint2: points[p1])
  
}

It’s not the worst code in the world, but it’s not great. I was rewarded with a pretty path, so whee. Still, the code was screaming out that it wanted to be better.

I started by attacking the index work. Why not have an array that supported circular indexing by offering the next and previous items? So I built this:

public extension Array {
  /// Return the next element in a circular array
  subscript(progressing idx: Index) -> Element {
    idx == indices.index(before: indices.endIndex)
      ? self[indices.startIndex]
      : self[indices.index(after: idx)]
  }
  
  /// Return the previous element in a circular array
  subscript(regressing idx: Index) -> Element {
    idx == indices.startIndex
      ? self[indices.index(before: indices.endIndex)]
      : self[indices.index(before: idx)]
  }
}

Before you start yelling at me, I quickly realized that this was pretty pointless. Arrays use Int indexing and I had already written wrapping indices a billion times before. Just because I has the concept of a circle in my head didn’t mean that my array needed to. I pulled back and rewrote this to a variation of my wrap:

public extension Array {
  /// Return an offset element in a circular array
  subscript(offsetting idx: Index, by offset: Int) -> Element {
    return self[(((idx + offset) % count) + count) % count]
  }
}

Much shorter, a bit wordy, but you can offset in either direction for as far as you need to go. I did run into a few out of bounds errors before remembering that modulo can return negative values. I decided not to add in any assertions about whether idx was a valid index as arrays already trap on that, so a precondition or assertion was just overkill.

Next, I decided to design a PointCircle, a type made up of points in a circle. Although I initially assumed I’d want a struct, I soon realized that I preferred to be able to tweak a circle’s radius or center, so I moved it to a class instead:

/// A circle of points with a known center and radius
public class PointCircle {
  
  /// Points representing the circle
  public private(set) var points: [CGPoint] = []
  
  /// The number of points along the edge of the circle
  public var count: Int {
    didSet { setPoints() }
  }
  
  /// The circle radius
  public var radius: CGFloat {
    didSet { setPoints() }
  }
  
  /// The circle's center point
  public var center: CGPoint {
    didSet { setPoints() }
  }
  
  public init(count: Int, radius: CGFloat, center: CGPoint = .zero) {
    (self.count, self.radius, self.center) = (count, radius, center)
    setPoints()
  }

  /// Calculate the points based on the center, radius, and point count
  private func setPoints() {
    points = (0 ..< count).map({ idx -> CGPoint in
      let theta = CGFloat(idx) * (2 * CGFloat.pi / CGFloat(count))
      return CGPoint(x: center.x + radius * cos(theta), y: center.y + radius * sin(theta))
    })
  }
  
}

I added observers to each of the tweakable properties (the radius, point count, and center), so the circle points would update whenever these were changed. By the way, this is a great example of when not to use property wrappers. Wrappers establish behavioral declarations, which this is not. My circle uses the observers instead to maintain coherence of its internal state, not to modify, limit, or expand type side effects for any of these properties.

Now I could easily create a circle and play with its points:

let circle = PointCircle(count: 20, radius: 100)
let path = UIBezierPath()
for (point, index) in zip(circle.points, circle.points.indices) {
  path.move(to: circle.center)
  path.addCurve(to: point,
                controlPoint1: circle.points[offsetting: index, by: 1],
                controlPoint2: circle.points[offsetting: index, by: -1])
}

I decided not to add some kind of API for passing a 2-argument (point, index) closure to my circle instance. It doesn’t really add anything or make much sense to do that here. It wouldn’t produce much beyond a simple for-loop, and the point here is to build a Bezier path, not to “process” the circle points.

My goal was to build enough support to allow me to iterate through the points and reference adjacent (or further offset) points to build curves. This does the job quite nicely.

It didn’t feel quite finished though. I wanted to add a little extra because one of the things I often do with this kind of drawing is create stars and points and loops using offsets from the main radius, often interpolated between the main points on the circle’s edge. Because I had built such a simple class, adding an extension for this was a snap:

extension PointCircle {
  /// Returns an interpolated point after a given index.
  ///
  /// - Note: Cannot pass the existing radius as a default, which is why the greatest finite magnitude is used
  public func interpolatedPoint(after idx: Int, offsetBy offset: CGFloat = 0.5, radius r: CGFloat = .greatestFiniteMagnitude) -> CGPoint {
    let r = r == .greatestFiniteMagnitude ? self.radius : r
    let theta = (CGFloat(idx) + offset) * (2 * CGFloat.pi / CGFloat(count))
    return CGPoint(x: center.x + r * cos(theta), y: center.y + r * sin(theta))
  }
}

The most interesting thing about this is that you cannot use a type member to default a method argument, which is why I ended up defaulting it to `greatestFiniteMagnitude`. It seems to me that it would be a natural fit for the Swift language to allow that kind of defaulting. In this case, it would say: “If the caller doesn’t specify a radius, just use the one already defined by the instance.” What do you think? Is that too weird an ask?

To wrap up, here’s an example using the interpolation:

let path2 = UIBezierPath()
for (point, index) in zip(circle.points, circle.points.indices) {
  path2.move(to: point)
  path2.addCurve(to: circle.points[offsetting: index, by: 1],
                 controlPoint1: circle.interpolatedPoint(after: index, offsetBy: 0.33, radius: circle.radius * -2),
                 controlPoint2: circle.interpolatedPoint(after: index, offsetBy: 0.67, radius: circle.radius * -2))
}

All the shapes at the start of this post are created from this and the preceding loop by tweaking the curve parameters. What pretty results will you come up with? If you build something particularly lovely, please share. I’d love to see them!

Reading stdin on the fly

Shai Mishali asks, “Is there something like readLine that lets me read stdin as the user types instead of waiting for an entire line?” The readLine function waits until the user presses enter or otherwise recognizes EOF to process input.

A little web search led me to this SO post, which is  based on this example, using termios, the Unix API for terminal I/O. After looking through both posts, I built a RawMode type to support direct input based on that code because nothing makes me happier than messing with solutions to make them a little swiftier.

To use this, you fetch bytes until you catch an EOF. It’s interesting to test both direct keyboard entries as well as pasting complex emojis. As I was working on this on both 10.14 and 10.15, I was mildly startled when my initial test code stopped working when I moved to 10.14. UnicodeScalar does not offer a utf8 view until 10.15:

extension Unicode.Scalar {
  @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
  @frozen
  public struct UTF8View {
    @inlinable
    internal init(value: Unicode.Scalar) {
      self.value = value
    }
    @usableFromInline
    internal var value: Unicode.Scalar
  }

  @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
  @inlinable
  public var utf8: UTF8View { return UTF8View(value: self) }
}

So thank you, Swift team, for giving us that. It’s a nice addition to the language!

Anyway, if you have a different approach or you can see ways to improve my take further, drop a comment and let me know.

Bad things: Extension Access Control

Swift extends the courtesy of an access control annotated extension to its top level members. I’m going to call this “inheritance”, but I know there’s a better name for this but I just don’t know what it is.

Consider the following:

// Base type is public
public struct MyStruct {}

// Here, the extension is declared public, so each top level member
// "inherits" that access level.
public extension MyStruct {
  // This is public even if it is not annotated
  static var firstValue: String { return "public" }

  // This is also public but the compiler will warn.
  public static var secondValue: String { return "public but warned" }

  // This class is also public via "inheritance" 
  class PublicSubclass {
    // However, its members must be annotated. This is public
    public static let publicValue = "public"
    // This defaults to internal
    static let internalValue = "internal"
  }
}

In this example, firstValue inherits the public access level from the MyStruct extension. The explicit annotation for secondValue is warned by the compiler as unnecessary.  If you treat warnings as errors, that’s a problem.

Each of the static properties are accessible outside the module except for internalValue, as even in a public class declaration, its members do not inherit its control level:

Before I start putting some preliminary style guidance out there, I’d like to point out a few more things about this. Here’s a second example:

internal class InternalType {}

extension InternalType {
  public static var value: String { return "value" }
}

Swift compiles this code without error. It is clearly a developer-sourced issue. The intent to make the member public is fundamentally flawed. as it exceeds the type’s access control level. This issue also exists outside of extensions, where the compiler will not warn on too-high levels for direct type members:

internal class AnotherInternalType {
  public var value = "value" // no warning
}

You’d imagine this is a place where the compiler should up its game, no? This is a point of code that is technically functional and compilable but whose specification undercuts the documenting nature of using access control. Shouldn’t the annotation be limited and warned here?

The compiler will find mismatches between the extension ACL and the type ACL:

And that’s where the problem comes in because the guidance I’m working on says: “Do not annotate extensions with access control levels except when working with trivial utilities”. Skipping extension ACL ensures that you can meaningfully and intentionally add access control to each member declared within that extension. Each access level is co-located with the declaration it decorates. This makes your code more easily audited and its access levels will be immediately apparent as to intent and implementation.

What are your thoughts? Can you think of any reasons why extensions should ever be ACL’ed in production code? And is this just a bug/language enhancement thing or is there something I’m missing. Thanks in advance for your feedback.

Teaching collections: shifting paradigms and breaking rules

Just because some things look alike and may act alike at some level, doesn’t mean that they should be taught at the same time, under a unified umbrella of learning. Consider bagels and donuts. They are both toroids . You can layer several instances onto a stick for storage or serving. You can cut them both in half. If you have no taste or sanity, you can place custard — or, cream cheese, salmon, onions, and capers — interchangeably between the two sides of either item.

Despite these common API surfaces, their use-cases, edge conditions, and recipes share little overlap. Conformance to ToroidFoodstuff does not correlate with each preparation of dough, the cooking process, or the serving and accoutrements associated with either food.

So why do we always have to lump arrays, sets, and dictionaries into a single lesson on collections?

A new language learner has little interest in traversing dictionaries, although it’s possible, or taking a set’s prefix, which is also allowed. Nor are new learners always prepared to take on optionals, the core return value for dictionary lookups, early in the language learning process.

I’ve recently spent some time helping to outline an introductory sequence for Swift learning. I pitched eliminating collections as a single topic unto itself. I want to reject superficial similarity and build language skills by introducing simple, achievable tasks that provide measurable and important wins early in the learning process.

Take arrays. They can store numbers and strings and more. You can grow them, shrink them, slice them. They have a count. They have indexes.  Arrays are perfectly matched with iteration in general and for-in loops in particular. Arrays and for-in iteration work hand-in-hand. So why not learn them together?

The answer is generally that arrays belong with collections and for loops belongs within a larger set of iteration topics. Ask yourself whether new coders actually need while and repeat-while loops in their initial approach to the language? How often in normal Swift coding do you reach for those two for simple reasons in simple code?

I’m not saying while-loops shouldn’t be taught. I’m trying to figure out what sequence of incremental learning provides new Swift developers with the most coherent set of basic tools they need to express themselves and expand their understanding over time.

Every classroom minute spent mastering while is a minute that could expand and practice for. Introductory lessons should focus on the core terms and patterns most commonly used in the workplace. Expressive language vocabulary can always be expanded through practice and engagement. Classroom minutes represent the restricted path.

Dictionaries, I argue, should be taught late. Every lookup is tied directly to optionals, a dictionary’s native return type. And optionals are quite a conceptually heavy topic. Dictionaries are the perfect pairing.  The type is a natural source of optional output, and an opportunity to discuss nil-coalescing and default fallbacks.

From there, you can pull in failable initializers, and optional chaining.  Dictionaries also lend themselves to advanced concepts like (key, value)-based for-in loop tuples, the key-value basics of Codable, and how custom structs relate to key-value coding, not to mention the entire conversation about nil, errors, try?, and more.

As for sets, well, I love sets and use sets, but are sets even appropriate for new learners outside of some sense of “completionism” learning? Should they be taught only because they’re one of the “big three” collection types? I’d argue that people should learn sets when they are already proficient in core language basics, not in the most introductory setting.

For example, you can tie sets into a lesson on view touches. Just because they’re a collection doesn’t mean that the newest students have to learn every collection right away, just as they don’t need to learn NSDictionary, NSArray, and AnyObject, and so forth, in the first days or weeks of exposure to Swift.

Trying to structure a plan to create a solid foundation of incremental learning is a challenging task for any non-trivial topic. When it comes to Swift and Cocoa/Cocoa Touch with its vast range of potential interests, ask the questions: “What core concepts and patterns best reward the language learner with immediate benefit?”, “What grouping conventions should be tossed overboard to better focus on the skills with highest returns?”, and “What critical paths allow learners to proceed towards measurable skills and performance with the least overhead?”

Justify each topic with an answer that’s not “it’s covered that way in the Swift Programming Language book”, especially when working with new learners versus developers moving into the language with existing programming experience. And even when teaching more experienced students, let the daily realities they’re trying to move towards mold the curriculum of what you choose to teach.

The best learners teach themselves. The best curriculum sets them up to do so.

Swift 5 gives us Nice Things™: Custom string delimiters

Say, for whatever reason, you were in desperate need of Bill the Cat ASCII art in your app. Maybe you were very drunk and had a bet. Maybe you were working with some kind of Unix awk client. I dunno. Let’s just start with the proposition that this was a real and meaningful challenge in your life.

In Swift 4.2, you could use multiline triple-quoted strings. Multiline strings are great for preserving indentation and other formatting, plus as a bonus, you get embedded quotes for free. Let me show you an example of how this works.

Instead of:

"\"I don't think...\"\n\"Then you shouldn't talk,\" said the Hatter."

with its multiple escape sequences, Swift 4.x gave us:

"""
    "I don't think..."
    "Then you shouldn't talk," said the Hatter.
    """

Same results, less fuss. The triple-quote string delimiter replaces the one-quote, so you don’t have to use backslash escaping. Dialog flows freely in 4.x.

But what happens when your source uses backslashes, as does this Bill the Cat clip art?

// error: invalid escape sequence in literal
let billTheCat = """
<------- ____
  &&&    /    \  __ _____,
    `-- |  o   \'  `  &&/
       `|      | o  },-'
         \____( )__/
         ,'    \'   \
 /~~~~~~|.      |   .}~~~\
  ,-----( .     |   .}--.
        | .    /\___/
         `----^,\ \
                \_/
"""

Nearly every backslash triggers a compiler error as an invalid escape sequence. The others are subsumed into an unintentionally valid escape (like \'). You have inadvertent line escaping at the ends of the seventh and eighth lines as well.

You have to escape each backslash, losing the ability to evaluate your clip art source at a glance. Every escape pushes characters on that line one item to the right. Given that this is Bill the Cat, not much is lost aesthetically speaking, but the results are less maintainable and harder to visualize.

let billTheCat = """
<------- ____
  &&&    /    \\  __ _____,
    `-- |  o   \\'  `  &&/
       `|      | o  },-'
         \\____( )__/
         ,'    \\'   \\
 /~~~~~~|.      |   .}~~~\\
  ,-----( .     |   .}--.
        | .    /\\___/
         `----^,\\ \\
                \\_/
"""

The problem becomes more pronounced when you work with pre-escaped material instead of visual art. For example, you may have escaped JSON or XML you want to paste directly into an app’s string. Each stringity escape sequence is an error waiting to happen:

{\r\n  \"first_name\": \"John\",\r\n  \"last_name\": \"Smith\",\r\n  \"is_alive\": true,\r\n  \"age\": 27,\r\n  \"spouse\": null\r\n}

Enter Swift 5. Its custom delimiters work on escape sequences the way that multiline strings work on dialog. Just add a pound sign (#) to each end of your string and your backslashes are perfectly preserved without hand edits or audits:

// Perfect Bill
let billTheCat = #"""
<------- ____
  &&&    /    \  __ _____,
    `-- |  o   \'  `  &&/
       `|      | o  },-'
         \____( )__/
         ,'    \'   \
 /~~~~~~|.      |   .}~~~\
  ,-----( .     |   .}--.
        | .    /\___/
         `----^,\ \
                \_/
"""#

Those extra pounds allow you to change the way Swift interprets escape sequences. They transform escapes from simple backslashes to \#. To insert a newline into a pound-delimited string, you type \#n and not \n. Similarly, string interpolation becomes \#(...interpolation...).

This system was inspired by the Rust programming language. Rust stacks one or more pounds at each end of a string (and prefixes the letter “r”) to create what it calls “raw strings”, that is strings without further escape sequence interpretation.  You cannot incorporate interpolation or coded tabs, new lines, or returns.

Swift adopts the extensible delimiters (skipping the ugly “r”) but retains its useful escapes, including string interpolation. Swift adapts each escape sequence to match the number of pound signs used at the start and end of the string. Instead of “raw strings”, Swift has, well, let’s call them “medium rare strings”. It allows you to paste and preserve raw formatting while retaining the ability to insert escape sequences.

In Swift 5, each of the following declares "Hello", even though they use a variety of single and multiline styles:

let u = "Hello" // No pounds
let v = #"Hello"# // One pound
let w = ####"Hello"#### // Many pounds
let x = "\("Hello")" // Interpolation
let y = #"\#("Hello")"# // Interpolation with pound
let z = """ // Multiline
    Hello
    """
let a = #""" // Multiline with pound
    Hello
    """#

Here are the rules:

  • You must match the number of #-signs before and after the string, from zero to however many. “One” is almost always the right answer for “however many”.
  • When you use #-signs, you change the escape sequence from a single backslash to a backslash infixed with the same number of pound signs. A ##"Hello"##  string uses the \## escape sequence.
  • Anything that doesn’t match the closing delimiter is part of the string. To add """ to a multiline string without escaping, just change the delimiter with pound.
  • Use the least number of pound signs required for the results you need. Zero is best. One is fine. Two or more is very, very rare.

And that’s it. With this one small change, anyone writing code generation apps like PaintCode or Kite Compositor (or one of my many utilities), writing network code with escaped-JSON,  or including weird Bill the Cat clip art, can paste and go. Just add pounds as needed, without sacrificing the convenience of string interpolation or escape sequences.

SE-0200, which introduces this new behavior, is one of my favorite proposals I’ve ever worked on. I’ve been lucky enough to have had a working toolchain with these features (thanks John H!) since before the proposal was even adopted.  I can’t wait until Swift 5 debuts, allowing custom string delimiters to become part of everyone’s coding work as well.