Archive for December, 2018

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.

Musing on API names for trailing and functional closures

When a call returns a value, I almost always use in-line closures. I prefer to surround functional calls with parens. I know my style is not universally popular, as many developers prefer the look of raw braces. It’s not uncommon to see calls like this:

numbers.sorted { $0 < $1 }.forEach {
  print($0)
}

The functional sort is chained to the non-functional loop, both using braces. Mandatory functional parens do two things. They differentiate expressions and they add the clarity of role labels that are lost with trailing closures. Compare these with the preceding call:

numbers.sorted(by: { $0 < $1 }).forEach {
  print($0)
}

// or even

numbers.sorted(by: <).forEach { print($0) }

In each case, the combination of name and label (in this case, sorted(by:)) is clearer and more easily read. Many APIs are designed without initial labels for Void-returning closures. They’re intended from the start to act as language-like constructs, so adding labels is either superfluous or detracts from the call when omitted:

public func forEach(_ body: (Self.Element) throws -> Void) rethrows

Omitting labels shouldn’t cloud intent even when a closure meant for functional calls is used. I could imagine common API naming rules to help guide labels and functional use (for example, “omit labels for Void-returning closure arguments” or “include role hint labels for functional closure arguments used to process and pass through values”).

Such rules might help but there’s one class of closures that doesn’t normally follow. Completion handlers, especially those sourced from Cocoa and Cocoa Touch, are almost always labeled as completion or some close variant. They’re designed for non-returning (and often asynchronous) execution. For example, you might see:

func run(_ action: SKAction, completion block: @escaping () -> Void)

or

func dataTask(with: URL, completionHandler: (Data?, URLResponse?, Error?) -> Void) -> URLSessionDataTask

These items are normally called as trailing closures, so why shouldn’t their API naming follow suit? Wouldn’t it make more sense to have _ completionBlock: or _ completionHandler: than to use explanatory labels that are most commonly hidden when called?

What do you think? Let me know.

ISO-8601, YYYY, yyyy, and why your year may be wrong

The end of the year is rolling around and it’s time to remind everyone about that yyyy works the way you think it does and YYYY does not. Here’s a quick example to start:

Just because you test a format quickly with the current date and get back the result you expect, does not mean you’ve constructed your date format correctly.

Speaking of which, BJ Homer points out that you can just use “y”, as “yyyy” pads to 4 digits which doesn’t usually matter but isn’t always needed. Olivier Halligon adds, further, that not all calendars use 4 digit years. “For example the Japanese start a new era every time the emperor changes, resetting to year 1 in that era; we’re currently in year Heisei 30.”

To quote The Dave™: “Nooooooo…. Please use “y”, not “yyyy”. “yyyy” zero-pads years that aren’t four digits, and there are multiple calendars w/ 2 or 3-digits years (Japanese, Chinese, Republic of China). “y” is the natural length of the year: “30” for Japanese cal, “2018” for Gregorian, etc”

What you’re actually seeing with “Dec 24, 2017” is the first day of the last full week of the preceding year. It doesn’t matter what numbers you plug into the month (“MM”) or day (“dd”). The presence of YYYY in the date format without its expected supporting information reduces to “start of year, go back one week, report the first day”. (I’ll explain this more in just a little bit.)

Here are some examples, which you can check from the command line using the cal utility:

As Apple’s 2014-era date formatting guide points out:

A common mistake is to use YYYY. yyyy specifies the calendar year whereas YYYY specifies the year (of “Week of Year”), used in the ISO year-week calendar. In most cases, yyyy and YYYY yield the same number, however they may be different. Typically you should use the calendar year.

Unicode.org’s Unicode Technical Standard #35, Date Format Patterns goes into a little more depth:

[“Y” is] Year (in “Week of Year” based calendars). This year designation is used in ISO year-week calendar as defined by ISO 8601, but can be used in non-Gregorian based calendar systems where week date processing is desired. May not always be the same value as calendar year.

ISO 8601 uses a 4-digit year (YYYY) for “week of year” calendars from 0000 to 9999. If you’re into trivia, the years before 1583 are technically excluded except by special agreement between sending and receiving parties.

Anyway, if you’re going to use YYYY formats, you’ll want to use additional format elements that support “week of year” date construction. For example, consider the calendar for this upcoming January, which starts on Tuesday the 1st:

    January 2019      
Su Mo Tu We Th Fr Sa  
       1  2  3  4  5  
 6  7  8  9 10 11 12  
13 14 15 16 17 18 19  
20 21 22 23 24 25 26  
27 28 29 30 31

This year, January first can be considered as the first week of 2019 or the 53rd week of 2018, as the weeks overlap in the middle. Using e (the numeric day of the week) and ww (the ordinal week to count from), you can represent both dates correctly using the oddball YYYY formatting token.

Here are examples that use the week-of-year approach counting from both 2018 and 2019:

As you can see from this, when you use YYYY and do not supply an ordinal week or day, they both default to zero, which is why you get the behavior of the zeroth week (that is, the week before the first week) on the zeroth day (also, the first day of that week) for that calendar year, which is the week before the first week that overlaps the stated year. This explains the results of all those otherwise random late-December dates from earlier.

ISO 8601 should be updated in a few months, with a release somewhere around February.

From what I can tell, the first part revises the current standard and the second expands it. The only freely accessible human-viewable material I could find were the five-page TOC previews for 8601-1 and 8601-2.

(Hat tip: Thanks, Robin Malhotra)

Iterating across more than two sequences at a time in Swift

A few days back, I needed to iterate three sequences at once. While Swift supports zip, allowing you to zip two sequences together and iterate across item pairs, until variadic generics hits the language, there’s no way to directly zip three or more.

Until that kind of tech hits the language, you can construct nested tuples for your occasional zip-3 or zip-4 needs without overly straining readability as in this example:

for (value1, (value2, value3)) in zip(seq1, zip(seq2, seq3)) {
  // use value1, value2, value3
}

I thought I’d leave this here in case it was of help to anyone.

Adding syntax highlighting and source file support for TypeScript to Xcode

Thanks to a prior solution created by Steve Troughton-Smith for Lua, I was able to hack together an Xcode Plug-In (yeah, those still exist) for 10.1.

TypeScript repo is here at github.

To install, quit Xcode. Run setup.sh to add the xclangspec and ideplugin info to your ~/Library/Developer/Xcode folders. Then launch Xcode, agree to allow the plug-in to run, and then add your ts files.

The file inspector will still say they’re MPEG-2 Transport Stream files but you’ll be able to see the text, the text will be formatted, and you can use Xcode to search for content within the files. Let me know if it works for you.

The xcplugin and the xclangspec were easy to put together, because I just riffed on JavaScript’s syntax. Other languages will take a bit more work because you have to set up a list of keywords and their characters and syntax coloring rules, which may or may not lend themselves to easy lexer support.

Swift 5 Interpolation Part 3: Dates and Number Formatters

I’ve already posted about using string interpolation to customize Optional presentation and for coercing integer values via radix and to conditionalize text, and yet there is still so much more you can do with this new language feature.

Consider formatters. Both Swift and Cocoa/Cocoa touch support a number of these, ranging from numbers and currency to dates and times. They are a natural interpolation fit.

For example, dates are easy right out of the box. Just pass a formatter and you’re done. Note that I skip the formatter label. You’ll see why in just a second.

public extension String.StringInterpolation {
  mutating func appendInterpolation(_ value: Date, _ formatter: DateFormatter) {
    appendLiteral(formatter.string(from: value))
  }
}

For dates, it’s more about how do you create formatters than about interpolating them. Here’s the design I’m using right now:

public extension DateFormatter {
  /// Returns an initialized `DateFormatter` instance
  static func format(date: Style, time: Style) -> DateFormatter {
    let formatter = DateFormatter()
    formatter.locale = Locale.current
    (formatter.dateStyle, formatter.timeStyle) = (date, time)
    return formatter
  }
}

For example:

print("\(Date(), .format(date: .short, time: .none))") // 12/16/18

I left off the formatter: label because the call to format documents the role of the second argument.

I initially went with a convenience initializer, along the same lines, but the calls were uglier:

print("\(Date(), DateFormatter(date: .none, time: .long))") // 8:20:15 AM MST

I also tried static preset properties and option sets, as well as dateStyle:timeStyle: interpolation arguments as but none of them really felt as readable as the format(date:time:) approach.

Number formats are a bit harder as they only work with NSNumber, which means you either have to create interpolators for both BinaryInteger and FloatingPoint, or you have to use some magic. Brent Royal-Gordon tried helping me work with _ObjectiveCBridgeable but I couldn’t get it to work. For some reason, Swift just wouldn’t pick up, for example, Double.pi as a bridgeable value.

For right now, I have this, which I’m not particularly happy with:

public extension String.StringInterpolation {
  /// Interpolates a floating point value using a
  /// number formatter.
  mutating func appendInterpolation<Value: FloatingPoint>(_ number: Value, formatter: NumberFormatter) {
    if
      let value = number as? NSNumber,
      let string = formatter.string(from: value) {
      appendLiteral(string)
    } else {
      appendLiteral("Unformattable<\(number)>")
    }
  }
  
  /// Interpolates an integer value using a number formatter
  mutating func appendInterpolation<Value: BinaryInteger>(_ number: Value, formatter: NumberFormatter) {
    if
      let value = number as? NSNumber,
      let string = formatter.string(from: value) {
      appendLiteral(string)
    } else {
      appendLiteral("Unformattable<\(number)>")
    }
  }
}

Creating number and currency formatters with NumberFormatter() is an ugly and tedious task. For example, here’s a formatter that sets rounding, localization, padding, and digit count:

let formatter = NumberFormatter()
formatter.localizesFormat = true
formatter.roundingMode = .halfUp
formatter.minimumFractionDigits = 1
formatter.maximumFractionDigits = 4
formatter.paddingPosition = .beforePrefix
formatter.paddingCharacter = "0"
formatter.minimumIntegerDigits = 5

"\(Double.pi, formatter: formatter)" // 00003.1416
"\(5, formatter: formatter)" // 00005.0

There really should be better and Swiftier ways to express these formatting preferences. For one thing, the minimum and maximum stuff could be expressed as ranges specific to the whole and fractional parts. I’m not convinced there should be just one formatter type devoted to handling integers, floating point numbers, and currency. Why not three?

Integers, to my best understanding, don’t need to worry about localization. And why not throw radix control into the IntegerFormatter mix while you’re at it? I’d imagine a well-designed integer formatter would easily replace my radix/prefix/bytewise/width interpolation that I used in a recent post.

In fact, I think I’ll design exactly that. Off to Xcode…

Some fantastic coverage of interpolation from Olivier Halligon here: Part 1 and Part 2.

My prosaic kicking the wheels repo is over at GitHub.

(And I’m trying to redesign Olivier’s attributed strings because somehow I feel they should be enumeration cases with associated value payloads rather than static members.)

More fun with Swift 5 String Interpolation: Radix formatting

I’m still kicking the tires and enjoying the new string interpolation features in Swift 5. Today’s extension enables (optionally padded) radix-based interpolation. You interpolate a number and specify a radix, the numerical base used to present it.

For example:

"\(42, radix: .hex)" // 2a
"\(42, radix: .binary)" // 101010
"\(42, radix: .octal)" // 52
"\(0x2a, radix: .decimal)" // 42
"\(15, radix: .hex, prefix: true, toWidth: 2)" // 0x0F

With padding you can ensure, for example, that a non-wide color is presented using two digits per color, with or without a prefix. Start with 15 and end up with F, 0F, or 0x0F , as desired.

It’s a simple extension for a task I use pretty regularly. I decided to use lowercase prefixes (0x and 0b) and uppercase hex (7F vs 7f). If you’d rather swap that out, change the prefix property and/or the first line in the interpolation:

public extension String.StringInterpolation {
    /// Represents a single numeric radix
    enum Radix: Int {
        case binary = 2, octal = 8, decimal = 10, hex = 16
        
        /// Returns a radix's optional prefix
        var prefix: String {
             return [.binary: "0b", .octal: "0o", .hex: "0x"][self, default: ""]
        }
    }
    
    /// Return padded version of the value using a specified radix
    mutating func appendInterpolation<I: Binary Integer>(_ value: I, radix: Radix, prefix: Bool = false, toWidth width: Int = 0) {
        
        // Values are uppercased, producing `FF` instead of `ff`
        var string = String(value, radix: radix.rawValue).uppercased()
        
        // Strings are pre-padded with 0 to match target widths
        if string.count < width {
            string = String(repeating: "0", count: max(0, width - string.count)) + string
        }
        
        // Prefixes use lower case, sourced from `String.StringInterpolation.Radix`
        if prefix {
            string = radix.prefix + string
        }
        
        appendInterpolation(string)
    }
}

I haven’t had a chance to test this much so if you see any issues, please let me know.

I have more to follow with more general NumberFormatter approaches that extend the interpolator (thanks, Dave DeLong!) and some fun suggestions and examples that will cover the new custom string delimiters.

Update James Dempsey writes:

In your post “More fun with Swift 5 String Interpolation: Radix formatting”, I noticed one very minor thing. The String initializer that takes a value and a radix also has an uppercase parameter. So the code
var string = String(value, radix: radix.rawValue).uppercased()
could be
var string = String(value, radix: radix.rawValue, uppercase: true)
I’m guessing that saves the tiny bit of work of creating a new string and transforming the old string. Definitely a minor point, but I always enjoy and find useful the precision of your explanations, so I thought you’d be interested.
Thank you, James!

The Beauty of Swift 5 String Interpolation

Thanks to SE-0228, you can control exactly how you want string interpolations to print. Thank you Brent for giving this to us. It’s a doozy! Let me share some examples.

Consider printing optionals. You use:

"There's \(value1) and \(value2)"

And get an instant warning:

You can click the fixes to suppress the warning but you’ll still get an output that looks like this: “There’s Optional(23) and nil”.

"There's \(String(describing: value1)) and \(String(describing: value2))"

Now you can strip the “Optional” and produce “There’s 23 and nil”, allowing you to print values directly:

extension String.StringInterpolation {
    /// Provides `Optional` string interpolation without forcing the
    /// use of `String(describing:)`.
    public mutating func appendInterpolation(_ value: T?, default defaultValue: String) {
        if let value = value {
            appendInterpolation(value)
        } else {
            appendLiteral(defaultValue)
        }
    }
}

// There's 23 and nil
"There's \(value1, default: "nil") and \(value2, default: "nil")"

You might create a set of styles and custom interpolation to support consistent presentation for optional output:

extension String.StringInterpolation {
    /// Optional Interpolation Styles
    public enum OptionalStyle {
        /// Includes the word `Optional` for both `some` and `none` cases
        case descriptive
        /// Strips the word `Optional` for both `some` and `none` cases
        case stripped
        /// Uses system interpolation, which includes the word `Optional` for
        /// `some` cases but not `none`.
        case `default`
    }
    
    /// Interpolates optional values using a supplied `optStyle` style
    public mutating func appendInterpolation(_ value: T?, optStyle style: String.StringInterpolation.OptionalStyle) {
        switch style {
        // Includes the word `Optional` for both `some` and `none` cases
        case .descriptive:
            if value == nil {
                appendLiteral("Optional(nil)")
            } else {
                appendLiteral(String(describing: value))
            }
        // Strips the word `Optional` for both `some` and `none` cases
        case .stripped:
            if let value = value {
                appendInterpolation(value)
            } else {
                appendLiteral("nil")
            }
        // Uses system interpolation, which includes the word `Optional` for
        // `some` cases but not `none`.
        default:
            appendLiteral(String(describing: value))
        }
    }
    
    /// Interpolates an optional using "stripped" interpolation, omitting
    /// the word "Optional" from both `.some` and `.none` cases
    public mutating func appendInterpolation(describing value: T?) {
        appendInterpolation(value, optStyle: .stripped)
    }

}

// "There's Optional(23) and nil"
"There's \(value1, optStyle: .default) and \(value2, optStyle: .default)"

// "There's Optional(23) and Optional(nil)"
"There's \(value1, optStyle: .descriptive) and \(value2, optStyle: .descriptive)"

// "There's 23 and nil"
"There's \(describing: value1) and \(describing: value2)"

Interpolation isn’t limited to tweaking optionals. Say you want to control whether a string is added without having to use a ternary expression with an empty string:

// Include on success (Thanks, Nate Cook)
extension String.StringInterpolation {
    /// Provides Boolean-guided interpolation that succeeds only when the condition
    /// evaluates to true.
    mutating func appendInterpolation(if condition: @autoclosure () -> Bool, _ literal: StringLiteralType) {
        guard condition() else { return }
        appendLiteral(literal)
    }
}

// Old
"Cheese Sandwich \(isStarred ? "(*)" : "")"

// New
"Cheese Sandwich \(if: isStarred, "(*)")"

There’s lots more you can do and it’s all exciting and fun.

Xcode Symbology Challenge! Find examples, identify icons, gain fame and glory

You know those little icons in the Xcode developer docs? Like the 4 squares for frameworks or the M for method? How many can you find and give examples for? Also how many can you identify off the top of your head? Do you know what each of these are and what they represent?

What follows is an exhaustive list sourced from an internal Xcode framework. For each of the following, your challenge is to describe what the icon looks like and offer an example that uses the icon. For example “T” is a type alias. You can find one by following UIKit > Drawing > UIGraphicsPDFRenderer.DrawingActions or searching for DrawingActions.

  • article
  • category
  • class
  • class extension
  • constant
  • endpoint
  • enum
  • extension
  • field
  • framework
  • function
  • group
  • local_variable
  • macro
  • method
  • object
  • operator
  • property
  • protocol
  • sample code
  • struct
  • subscript
  • typedef
  • union
  • variable

Have fun and drop a comment with a link to your finds. Please don’t put answers here directly as that may spoil the challenge for others.