Choosing the Best Expression

A recent objc.io post on Phantom Types included the following snippet:

struct FileHandle<A> {
    let handle: NSFileHandle
}
struct Read {}

func openForReading(path: String) -> FileHandle<Read>? {
    return NSFileHandle(forReadingAtPath: path).map { FileHandle(handle: $0) }
}

Instead of using map here, I feel that an if-let would be more appropriate. If I were writing openForReading(path:), I would have written it like this:

func openForReading(path: String) -> FileHandle<Read>? {
  if let fh = NSFileHandle(forReadingAtPath: path) {
    return FileHandle(handle: fh)
  } else {
    return nil
  }
}

Sure, it‘s a bit more verbose, but I feel like it‘s a better expression of the program‘s meaning.

When a programming language gives you multiple ways of expressing the same idea, the expression the programmer chooses will highlight a specific aspect of that approach. Here, the map expression is effectively a choice to emphasize the definition of a function whose domain is the possible return values of the NSFileHandle initializer. Because the domain of a function is a set, the reader is suddenly concerned that there is a collection of NSFileHandles being mapped into FileHandles!

Understanding what this function actually does requires two pieces of background information: that NSFileHandle.init(forReadingAtPath:) returns an Optional (so it may return nil if given a bad path), and that Optional<T>.map exists to treat a non-nil Optional as if it were a one-element set. Then it becomes apparent that the writer‘s intent is to transform only vaild NSFileHandles into FileHandle<Read>s.

Surely programmers cannot be absolved from having some knowledge of the framework and the standard library they are using, but let’s contrast this approach with the alternative. The if-let formulation emphasizes the specific elements for which execution is defined. It also specifically highlights that one of those elements is nil, and thus it‘s fairly apparent to the reader that the purpose of the construct is to define correct behavior for success and failure cases. No need to have memorized whether NSFileHandle has a failable initializer. No need to know that the Optional<T>.map shortcut exists.

That said, we do lose the assurance that all possible cases are covered, which map provides. We could gain that back with a (never-executed) else clause, or we can rely on the explicitness of the nil test to assure the reader that only two possible cases exist and that both are covered. Percentage-wise, we also gain a fair bit of verbosity, but in absolute terms it‘s not so much. In fact, I‘d argue that the map version is actually compressing too much information into too few characters.

Fortunately, we can combine if-let‘s readability with map‘s terseness and assurance of having defined a total function by defining a function-pipelining operator |->? like this:

infix operator |->? { associativity right }
public func |->?<T, U> (v: T?, f: T? -> U?) {
  if v == nil {
    return nil
  } else {
    return f(v)
  }
}

One can imagine that this operator is the sibling of a |-> which does not deal in Optionals. The trailing ? makes the behavior of this operator clear to the reader by analogy to the ?. (optional-chaining) and ?? (nil-coalescing) operators.

Now we can rewrite openForReading(path:) like this:

func openForReading(path: String) -> FileHandle<Read>? {
  return NSFileHandle(forReadingAtPath: path) |->? { FileHandle(handle: $0) }
}

Of course, we could convert the anonymous closure into a named function, perhaps named something like makeReadHandle. That minimizes the complexity of each element of the pipeline. Here, it might not be that big of an advantage, but if I stuck another step on the end of the pipeline, I‘d consider it rather strongly.

A Cascade of Table View Bugs

Yesterday I wrote some code to hide the Trash location in our document picker when it’s empty. Today, I got a bug report that attempting to add or remove a cloud storage location in the document picker would now crash with an exception thrown by UITableView. These didn’t sound all that related other than timing and both involving the document picker.

And at first, all the evidence told me they were not related. But thanks to a combination of overlapping bugs it took me over an hour, a fair bit of disassembly, and some moral support from my coworker Jake to track down the origin of the bug.

[Read more…]

Implementing -[UIApplication targetForAction:to:from:]

Updated: It turns out that UIKit likes to set the first responder to nil. At that point, my technique for finding the first responder winds up returning the UIApplication instance, which nullifies the technique. I’ve rolled back this change from our codebase; I’ll leave the blog post here, but I can’t advise anyone adopt this technique.

One of the best patterns that UIKit inherited from its older brother is the responder chain. It is a fantastic way to decouple UI controls from their targets and enables the same control to perform its function even as the user interface or controller layer changes around it.

On iOS, like on the Mac, UIApplication plays a central role in dispatching events to the responder chain: -[UIApplication sendAction:to:from:forEvent:] starts with the first responder and walks up the chain to find an object that can handle the provided action. But what if you just need to know whether such a responder exists, or you need to ask it further questions before you dispatch the action?

[Read more…]

UIPresentationController is (currently) a deficient API

iOS 8 brings a new and welcome class to UIKit: UIPresentationController, which reifies the presentation of view controllers in a configurable object whose lifetime can also be used to more cleanly manage auxiliary UI elements associated with that presentation.

Conceptually, popovers are a form of presentation, so they are now managed via a subclass of UIPresentationController, logically named UIPopoverPresentationController. Unfortunately, the actual API design surrounding this class leaves a lot to be desired.

[Read more…]

-targetViewControllerForAction:sender: is smarter than it seems

The new -[UIViewController targetViewControllerForAction:sender:] method (and its related methods, -showViewController:sender: and -showDetailViewController:sender:) in iOS 8 takes a clever responder chain-based approach to showing view controllers in a size-class-adaptable way.

Basically, all UIViewController instances respond to -showViewController:sender: and -showDetailViewController:sender:, but their implementations use -targetViewControllerForAction:sender: to find the appropriate view controller to actually do the showing. In the case of -showViewController:sender:, this is likely an enclosing UINavigationController, and in the case of -showDetailViewController:sender:, this is likely an enclosing UISplitViewController.

[Read more…]

An Auto Layout Adventure: NSCell, -intrinsicContentSize, and -constraintsAffectingLayoutForOrientation:

Recently my coworker Tom was having a hard time with converting a Mac NIB to Auto Layout. The NIB contained a split view; on the left was an instance of OACalendarView, and on the right was a scroll view. The holding priorities of the left and right panes were 251 and 250, respectively, and the scroll view had a required width constraint of greater-than-or-equal-to 150.

For some reason, the left pane insisted on being as wide as possible, squeezing the right pane down to 150 points wide. Dragging the splitter had no effect. How do we figure this one out?

[Read more…]

How to think about UIScrollView.contentInset

Up until three months ago, my time at the Omni Group had been spent programming solely for the Mac—I hadn’t written any iOS code professionally, and I’d only dabbled the slightest bit on the side.

That all changed when iOS 7 was announced, and I’ve now spent a solid three months as an iOS developer. For the most part, it was an easy transition; I’d picked up quite a bit of iOS knowledge peripherally, and I learned a lot more very quickly through hands-on experience. But one thing bedeviled me: UIScrollView.

[Read more…]

Auto Layout Slides and Video Available

On Thursday, January 10, I gave a talk at Seattle Xcoders about Auto Layout, explaining the benefits and workings of this new technology and sharing some tips learned from our adoption of auto layout.

I’ve uploaded the slides from my talk. I’ll upload the video once I’ve found a place to put it.

Update: Thanks to Paul Goracke of Seattle Xcoders, the video of my talk is now available as well. Unfortunately, for some reason the cursor got disassociated from the actual mouse position during the demos, and I don’t have any way to fix it. Sorry! (rdar://problem/13011198)

WWDC of the Future

So WWDC 2012 was announced at early o’ clock and sold out in less than two hours. New restrictions on multiple purchases didn’t do anything to stave the ever-shortening window. As compensation for all the interested developers who won’t get to go to WWDC this year, Apple has promised to quickly post the session videos online (as they’ve done in the past few years).

Which leads me to ask: why is WWDC still worth attending? WWDC’s allure has always been the exclusive combination of three features: the sessions, the labs, and the social interaction with the worldwide Cocoa community. Now that the sessions can be gotten online mere days after the conference (and have lately been repeated locally during the Tech Talk series), and much of the community wasn’t even awake to purchase tickets, the only remaining feature of WWDC is the direct access to Apple engineers provided by the labs.

Maybe it’s time to think of a post-WWDC world. Or perhaps a world in which an event named WWDC still exists but bears no resemblance to the event we currently know.

[Read more…]