Encapsulate a Process in a Single Line Using Bind and Good OO Design

Watch Saul Mora’s AltConf presentation “Object-Oriented Functional Programming: The Best of Both Worlds!” to learn more about real world use of bind and other functional concepts in object-oriented programming. His examples are really good.

His use of bind() to chain calls which return optionals is even better with a custom operator as syntactic sugar: >>=. Then you can see the whole process with meaningfully named action steps in a single line.

I’m not a fan of custom operators per se, but I see their use as long as they adhere to some kind of convention. If they don’t, they make people lives too hard too easily.

Saul’s example contains a set of functions or closures that take an optional and transform it into another optional to find out if a file as some URL has expired. I stripped the implementation of the steps to stress the chaining:

func expired(fileURL: NSURL) -> Bool {
    let fileManager = NSFileManager()
    var error: NSError?

    let filePath: String? = fileURL.path
    let fileExists: (String) -> (String?) = // ...
    let retrieveFileAttributes: (String) -> ([NSObject: AnyObject]?) = // ...
    let extractCreationDate: ([NSObject:AnyObject]) -> NSDate? = // ...
    let checkExpired: NSDate -> Bool? = // ...

    return filePath 
        >>= fileExists 
        >>= retrieveFileAttributes 
        >>= extractCreationDate 
        >>= checkExpired ?? false
}

Compare that to the “before” code:

let fileManager = NSFileManager()
if let filePath = fileURL.path {
    if fileManager.fileExistsAtPath(filePath) {
        var error: NSError?
        let fileAttributes = fileManager.attributesOfItemAtPath(filePath, error: &error)
        if let fileAttributes = fileAttributes {
            if let creationDate = fileAttributes[NSFileModificationDate] as? NSDate {
                return creationDate.isBefore(NSDate.oneDayago())
            }
        }
        else {
            NSLog("No file attributes \(filePath)")
        }
    }
}

Using bind to chain operations is compatible with “Tell, Don’ Ask”. Even though chaining requires the operations to return a value, reasoning about the chain as a whole is a lot easier. The process fits into a single line. Imagine how splitting up action steps into chained helper objects would look: you’d be jumping between source files forever.

Have both in your toolkit to respond to new challenges appropriately.