Archive for September, 2016

Finishing up Swift From Two to Three

twothreescaled

I’m getting close to wrapping up my latest little self-published Swift book. Like Playground Secrets and Documentation Markup, the book will be available on iTunes and LeanPub. It’s written for anyone who has stayed in Swift 2.3 so they could keep shipping code but who now is looking to move towards Swift 3.

Here are some sample pages to give you a feel for what’s coming up.

As always, if you have any feedback or requests, please let me know. Does this sound like a book you might purchase? I’d love to hear from you.

Thanks again for all the support you give me, my blog, and my books. It’s appreciated beyond measure.

Dear Erica: How do you create `Never` callbacks?

Vivien Leroy writes: I tried using Never for my API module callbacks but couldn’t really figure out how to use it when my callbacks contains guards. Here’s an example:

Capture d’écran 2016-09-06 à 17.15.59

Do you have any hints on how to properly use Never for such case?

While you don’t really need a Never return type for completion methods, especially those that don’t exit the application, you can work around guard conditions by skillful use of do clauses.

You might create a Never-based completion type:

typealias CompletionNever = () -> Never

func functionWithNeverCompletion(completion: CompletionNever) 
{
    // ... do interesting things ...
    completion()
}

Guard conditions require you to exit scope. Never mean you cannot  return from your function. So, instead, add a simple do-scope layer:

functionWithNeverCompletion {
    alldone: do {
        guard somecondition else { break alldone }
        print("Hello")
    }
}

This ensures you can perform all the standard guard conditions, including Boolean tests, optional binding, availability checks, and so forth, while maintaining the “no return” integrity of the handler.

Guarding with diagnostics

So I was reading a question someone passed by me today, and completely ignoring their question for the moment, my eye was caught by the following pattern:

let firstName: String = ""
let lastName: String = "Smith"

// Choice 1: Original Recipe
func basicGuard() -> Any? {
    guard !firstName.isEmpty 
        else { print("firstName can't be empty"); return nil }
    guard !lastName.isEmpty 
        else { print("lastName can't be empty"); return nil }
    return "something"
}

And I was thinking, surely there’s a nicer way to do this. So just brainstorming, I came up with the following two:

/*
   Debug flag is set in Build Settings > Custom Flags > Other Swift Flags
   See: http://i.imgur.com/GA7M4T4.jpg
*/

// Choice 2: Using Infix Operator

func debugOnlyPrint(_ items: Any..., separator: String = " ", terminator: String = "\n") {
    #if debug
        print(items.map({ "\($0)" }).joined(separator: separator), terminator: terminator)
    #endif
}

infix operator **
func **(condition: Bool, message: String) -> Bool {
    if !condition { debugOnlyPrint(message) }
    return condition
}

func infixoperator() -> Any? {
    guard
        !firstName.isEmpty ** "firstName cannot be empty",
        !lastName.isEmpty ** "lastName cannot be empty"
    else { return nil }
    return "something"
}

// Choice 3: Using an enforce function

func enforce(_ rule: String, _ condition: @autoclosure () -> Bool) -> Bool {
    let passing = condition()
    if !passing { debugOnlyPrint(rule) }
    return passing
}

func enforcement() -> Any? {
    guard
        enforce("firstName cannot be empty", !firstName.isEmpty),
        enforce("lastName cannot be empty", !lastName.isEmpty)
    else { return nil }
    return "something"
}

So let me ask you, of these three, which do you like the best? And why?

Moving on to the question that was actually asked: what’s an easy way to print a return value for debugging? You can use any of a number of diagnostic solutions, I kind of like this one:

func here(_ note: String = "", line: Int = #line) -> Bool {
    if note.isEmpty { debugOnlyPrint("[line \(line)] ", terminator: "") }
    else { debugOnlyPrint("[line \(line) \(note)] ", terminator: "") }
    return true
}

precedencegroup VeryLowPrecedence {
    associativity: right
    lowerThan: AssignmentPrecedence
}

infix operator ?* : VeryLowPrecedence

func ?*(_: Any, item: T) -> T {
    debugOnlyPrint(item); return item
}

To use this, place a call to here() followed by ?* in-line before your return item, for example, return here() ?* "something". It prints out the line number followed by the return value. Operating at a very low precedence enables the entire return expression to be evaluated before printing.

It’s Now or Never…

I totally forgot I promised to post about Never. So first some apology Elvis. And that done, let me introduce you to this new Swift 3 keyword.

SE-0102 removes the rarely-used @noreturn function type and replaced it with a dead-end return type:

/// The type of expressions that can never happen.
public /*closed*/ enum Never { /*no values*/ }

func foo() -> Never {
  fatalError("no way out!")
}

Using Never allows you to express the condition where a method or function, whether by dispatch (completion handlers, for example, although you generally don’t need Never for that use-case) or expected exit (for example, a usage() function in a command-line Swift app) will never return control back to the call site.

I haven’t used Never very much. To date, it’s mostly a command line thing for me, and one where I’m more testing the waters than using confident assurance.

// Fetch arguments and test for usage
var arguments = CommandLine.arguments
let appName = arguments.remove(at: 0).lastPathComponent
func usage() -> Never { print("Usage: \(appName) location1 location2"); exit(-1) }
guard arguments.count == 2 else { usage() }

The Swift compiler picks up the Never return type in the guard statement, accepting that the else clause leaves scope.

According to Joe Groff’s proposal, there are several advantages of using Never over @noreturn.

  • Never allows a function or method to throw: e.g. () throws -> Never. Throwing allows a secondary path for error remediation, even in functions that were not expected to return.
  • As a first class type, Never works with generics in a  way that the @noreturn attribute could not.
  • Never proactively prevents a function from claiming both a return type and no-return at the same time. This was a potential issue under the old system.

Joe writes in summary: “The net result is a simpler, more consistent, and more expressive model for handling nonreturning functions.”

Optional Flappity Mappity

Consider the following four functions. Off the top of your head, without cheating, can you tell me which ones will compile and which ones won’t? And can you tell me what the type of newDate will be for each function? (In these examples, dateFormatter is a DateFormatter, oneDayOffset is DateComponents, and calendar is Calendar.)

func tomorrowsDateString1(dateString: String) -> String? {
    let date = dateFormatter.date(from: dateString)
    let newDate = date.map{ calendar.date(byAdding: oneDayOffset, to: $0) }
    return newDate.map(dateFormatter.string(from:))
}

func tomorrowsDateString2(dateString: String) -> String? {
    let date = dateFormatter.date(from: dateString)
    let newDate = date.flatMap{ calendar.date(byAdding: oneDayOffset, to: $0) }
    return newDate.flatMap(dateFormatter.string(from:))
}

func tomorrowsDateString3(dateString: String) -> String? {
    let date = dateFormatter.date(from: dateString)
    let newDate = date.flatMap{ calendar.date(byAdding: oneDayOffset, to: $0) }
    return newDate.map(dateFormatter.string(from:))
}

func tomorrowsDateString4(dateString: String) -> String? {
    let date = dateFormatter.date(from: dateString)
    let newDate = date.map{ calendar.date(byAdding: oneDayOffset, to: $0) }
    return newDate.flatMap(dateFormatter.string(from:))
}

And now consider this cute little hack, which will probably ensure you end up in hell:

/// High precedence
precedencegroup HighPrecedence { higherThan: BitwiseShiftPrecedence }

/// .? contextually performs map or flatMap
infix operator .?: HighPrecedence

/// Performs an in-line operator-based flatMap
public func .?<T, U>(lhs: T?, transform: (T) throws -> U?) rethrows -> U? {
    return try lhs.flatMap(transform)
}

/// Performs an in-line operator-based map
public func .?<T, U>(lhs: T?, _ transform: (T) throws -> U) rethrows -> U? {
    return try lhs.map(transform)
}

Which gives you this little one-operator hackapalooza:

/// And no, you don't have to figure out if you need map or flatMap
func tomorrowsDateString(dateString: String) -> String? {
    let date = dateFormatter.date(from: dateString)
    let newDate = date.?{ calendar.date(byAdding: oneDayOffset, to: $0) }
    return newDate.?dateFormatter.string(from:)
}

Pray for my soul.

Operators, Operators, Operators: Introducing Precedence

Swift 3.0 does operators a new way. Instead of assigning a direct precedence, use precedence groups. The built in groups are:

BitwiseShiftPrecedence > MultiplicationPrecedence (left) > AdditionPrecedence (left) > RangeFormationPrecedence > CastingPrecedence > NilCoalescingPrecedence > ComparisonPrecedence > LogicalConjunctionPrecedence (left) > LogicalDisjunctionPrecedence (left) > TernaryPrecedence (right) > AssignmentPrecedence (right, assignment) > FunctionArrowPrecedence (right) > [nothing]

Plus there’s a DefaultPrecedence, which is higher than TernaryPrecedence.

Each precedence group may define a relationship, which when used in-module must always be higherThan another in-module precedence. You can use lowerThan to describe how a precedence relates to a precedence imported from another module. Relationships are optional. FunctionalArrowPrecedence does not use any relationships.

Each precedence group may define associativity, which is either left or right. Again, this is optional.

Finally, there’s a special notation for operators that perform assignments:

precedencegroup AssignmentPrecedence {
    associativity: right
    assignment: true
    higherThan: FunctionArrowPrecedence
}

You can easily create your own precedence groups:

/// High precedence
precedencegroup HighPrecedence { 
    higherThan: BitwiseShiftPrecedence 
}
/// Very high precedence precedencegroup VeryHighPrecedence {
    higherThan: HighPrecedence
}

For example, consider the following code:

let x = Optional(42)
let y = 5 + x ?? 2 // will not compile

This will not compile unless you parenthesize (x ?? 2) because the compiler cannot distinguish between (5 + x) ?? 2 and 5 + (x ?? 2). Although you might instinctively want to raise the precedence level for the nil-coalescing ?? operator, how would you expect the compiler to handle the following example, provided by Jacob Bandes-Storch:

let nextIndex = foundIndex ?? lastIndex + 1

You can instead work around this by creating a custom high-precedence nil-coalescing operator.

/// Create a new high-precedence operator
infix operator .?? : HighPrecedence

You conform the new operator definition to a precedence group. You do not define the operator’s characteristics in braces. Leave a space before the colon so it is clear that it is not part of the operator.

/// A high-precedence coalescing nil,
/// ensuring that coalescing occurs to
/// produce a value before applying value
/// to other operations
/// - Parameter lhs: an optional value
/// - Parameter rhs: a non-optional fallback value
/// - Returns: The coalesced result of `lhs ?? rhs`
///   performed at high precedence
/// ```
/// let x = Optional(42)
/// let y = 5 + x ?? 2 // won't compile
/// let y = 5 + x .?? 2 // will compile
/// ```
public func .??(lhs: T?, rhs: T) -> T {
    return lhs ?? rhs
}

This produces a variation on ?? that is guaranteed to be executed before any multiplication, addition, or bit-shifting operations.

Precedence groups don’t actually have to mention precedence. You can create operators that refer only to associativity:

precedencegroup LeftAssociativePrecedence {
    associativity: left
}

Unfortunately, the remains a slight bug in the compiler that does not allow you to declare:

postfix operator +? : LeftAssociativePrecedence

but you can still declare

postfix operator +?

Which allows you to convert any item to an optional without having to wrap it directly into an Optional enumeration:

/// Adds optionality by wrapping the
/// rhs value in an Optional enumeration
///
/// - Parameter lhs: a value
/// - Returns: The value wrapped as an Optional
/// ```
/// let x = 42+? // x is Int?
/// ```
public postfix func +?(lhs: T) -> T? { return Optional(lhs) }

This is just a taste of what you can do with Swift 3 optionals. More to follow.