Altconf saul mora cover?fm=jpg&fl=progressive&q=75&w=300

Object-Oriented Functional Programming

If a functional language is essentially “a language where you can take a function, and assign it to a variable”, as Saul Mora asserts, you might be surprised to hear that Objective-C would be classed as a functional language — or at least, “functional-ish”. There is much less surprise when it comes to Swift.

And yet, if Swift is a functional language, it is equally an object-oriented language. Despite apparent tensions, this mixing of paradigms is in practice quite a happy one. In this talk, Saul Mora introduces some common and recognizably functional operators such as map, bind, and apply, and shows us how these very simple functions help produce concise and powerful code. We end with a pragmatic call to embrace both worlds, as Swift itself does so well.


OO vs. Functional: We Are All Friends Here (0:00)

Object-oriented programming has been around for awhile. Just to show you that there are no hard feelings, I could have named this talk any number of ways, one example being “Functional Object-Oriented Programming.” There’s no bias here, we’re going to all be friends. But you can make some crazy names out of it, like Programming Oriented Functional Object.

What Is NOT “Functional”? (1:27)

Objects are something that you have dealt with for quite a while now. We’re very familiar with this paradigm, and we know how this works. We even have languages like Scala, Closure, and now Swift, that strongly embrace both paradigms: the object-oriented and the functional. But it’s unclear what “functional” means to many people. Swift is nice because it blends these concepts together, and so the real question is, “Will it blend?”

I think the easiest, and perhaps most straightforward way to answer this iy by figuring out what functional languages are not. The first thing that functional programming is not is that it isn’t statically typed. A functional language does not require static types. For instance, a language like Lisp, which is extremely functional, is not statically typed. All the awesome type checking in Swift does not make it functional. Generics too, however, are not required for a language to be functional. Generics are useful and nice to have in Swift. They make a lot of things easier, and make some tasks more syntactically easier to read. But, it’s not a requirement that the language has to have generics.

We also have overloaded operators. This worked really well for C++, which is why we’re getting this in Swift. Overloaded operators are definitely not something that you need to have in a functional language, although it does make a lot of code nicer and easier to read. Nonetheless, just the fact that things are easier to read does not make it a functional language. Sometimes it’s not easy to read as well. One of the other things that you might think is functional and required in a functional language are optionals. Optionals are a very special kind of monad that basically tell you if something is there or not, but they are not necessary for functional behavior. Although optionals are nice, they are not a requirement to have a functional language.

Functions are Value Types (3:08)

There’s really only one simple requirement: functions are value types. That means that you can take a function and assign it to a variable. That’s it! There are a number of languages that can do that, including one of my favorites: Objective-C. Because there are things like blocks in Objective-C, it is now by definition a functional language.

The way I like to think about functional languages is really simple. F(x) = y is a mathematical concept from your old, high school math course. The way that you express that in Swift is just by defining a function.

f(x: Int) -> Int

It looks very similar. The way that you actually embrace that in a functional programming language is by having a pipeline - a series of tubes. You build up this pipeline of functions, that ultimately ends up building your program.

map and Other Functional Operators (3:46)

Let’s talk about map. map is very common; it’s something that you might have seen even before you started using Swift. It’s a simple concept: suppose you have a collection of objects, perhaps some blue rounded rectangles, and all you want to do is transform each of these into some red circles. That’s a very simple map function. All it does is take every item in that list and convert it into the next form. It does all the iteration for you.

Get more development news like this

let numbers = [1, 2, 3, 4, 5]
var calculatedNumbers: [Int] = []
for value in numbers {
    calculatedNumbers.append(value * 2)
}

As far as code is concerned, we would typically do this in Objective-C or Swift by the brute force method. With a collection of numbers, we would iterate over them ourselves and append them to this temporary array - the brute force way to do it. Now, the nicer way to do it is to map your numbers:

let numbers = [1, 2, 3, 4, 5]
let calculatedNumbers = map(numbers) { $0 * 2 }

Instead of focusing on the iteration and the boilerplate for collecting intermediary values, we are letting something else compute the values for us. All that we’re defining in functional programming is the relationship. In this case, we’re just defining taht to be taking the double, or multiplying each number in the array by two. We’re really trying to extract just the core of the operation into a very small function. In this case, that function is that lambda, that $0 times two.

Declarative vs. Imperative (5:58)

A lot of times, this is pointed out as the difference between declarative versus imperative programming. Declarative is expressive with its syntax, in that it is making sure that the compiler can figure out the details of how to do things. On the other hand, imperative has you attempting to walk through all the details on your own.

I like to think of it more as the “what” versus the “how.” I wanted to define what I want, which in that example was all the numbers in that array by multiplied by two, versus “how,” which means I want to manually go through the array, item by item. Defining the “what” lets me parallelize that traversal function as I need to. It’s a very subtle difference, but once you start getting the hang of it, functional programming gets easier and easier.

Functional Example (7:02)

Let’s take a deep dive into some code and look at this old_and_busted_expired function.

func old_and_busted_expired(fileURL: NSURL) -> Bool

This is a really simple function. It takes a URL, hopefully on disk, and tells you if it is expired. If we just followed our procedural way of doing things, a simple implementation of this would be to use a lot of if let wrapping. This is a lot to read, so let’s take out some of the bottom return statements and focus more on the 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)")
        }
    }
}

This is typically known as the pyramid of doom. It doesn’t look like a pyramid because I’ve had to shrink it down. Nonetheless, there is a lot of if let unwrapping here. What is this function actually trying to do? It’s trying to compare two different dates, and one of them comes off the file system off the file attribute. Let’s look at some of the steps that are required to actually compute is expired for a file on disk.

First of all, we have to get the file path, and we want to see if that exists. We check the file manager, see if that exists, and then extract the attributes of that item. We can use some Cocoa APIs to get some dictionary attributes out of there. Once we get those, we want to extract the creation or the modification date out of those attributes. Then, we want to actually perform a nice little comparison function that I conveniently wrapped up in this extension on NSDate; I have a couple other convenience functions there too. These operations have to happen in order - the very last step in this cannot happen without the very first step action succeeding. This is why we have this if let unwrapping all over the place.

Step by Step (7:53)

Let’s try to think about this as a series of steps. We have to return the file path if it exists, and extract & unwrap the file attributes. I want to do that in one simple operation. I also want to get the modification date attribute, then compute one day ago. Next, I want to return that as the comparison - the result of actually comparing one day ago, in this case, with the actual value in that date. Now, we’ll go through this series of steps with the ultimate goal of converting this code into a more functional-oriented function.

The first step is unwrapping the file path. That’s pretty simple. We have a file URL, and we just ask for the path. We get that, and that’s our starting point.

let filePath = fileURL.path

In the next step, we want to see if that file exists. Here, we’ll create a little function and assign it to a variable using the properties of functional programming and Swift. The signature of the function is derived from our file path: the parameter is a string, and it will return an optional string. We’ll get to the reason it returns an optional in a while. What we’re basically doing is capturing the file manager that we have outside the closure and putting it through our Cocoa APIs. If the file exists at path, which is what file manager does for us, we return the path. If not, we return nil. We can actually do a check and get nil or not, which will be really important as we go along.

let fileExists : (String) -> (String?) =
{ path in
    fileManager.fileExistsAtPath(path) ? path : nil
}

After we’ve got the path, we want to get the file attributes out of that. The parameters and return type of this are significant. We can take a string because we just have a file path, and we return a dictionary - the attributes dictionary that’s returned from the NSFileManager. This result is optional because this may or may not have attributes based on whether or not that file is valid. Notice that this is slightly older Swift code (< v2.0) because it isn’t taking advantage of the new awesomeness of guard clauses and early returns, along with try-catches. This is a really concise function. The error is happening where you think it should, so the error handling is close to the program causing it, if it does exist. Otherwise, this tiny function will return the attributes.

let retrieveFileAttributes : (String) -> ([NSObject: AnyObject]?) =
{ path in
    var error: NSError?
    let attributes = fileManager.attributesOfItemAtPath(path, error: &error)
	
    if attributes == nil {
        NSLog("Unable to check \(path): \(error)")
    }
    return attributes
}

The next thing we want to do is extract the creation date from those attributes. If the previous function returned a dictionary of type [NSObject:AnyObject], this function’s purpose is to take that dictionary and extract the NSDate. In other words, it will take the value out of the dictionary and return the date you asked for. Hopefully you’re noticing a pattern in these function signatures. We have an object that is unwrapped, so it’s expected to be there all the time. This is a very safe parameter, and its return type is optional. Keep this signature in mind, as it’s important as well.

let extractCreationDate : [NSObject:AnyObject] -> NSDate?

Here is what the implementation might look like. I’m also going to make use of the fancy Swift syntax by using $0 as the first implicit parameter. This is expected to be of the type [NSObject:AnyObject]. It knows that it’s a dictionary, and so I can extract the data and optionally cast it as NSDate. That’s all this function does.

let extractCreationDate :
[NSObject:AnyObject] -> NSDate? =
{
    $0[NSFileModificationDate] as? NSDate
}

Now we have ended up with a series of these functions, whose signatures look like this:

let filePath:
    String?
let fileExists:
    String -> String?
let extractFileAttributes:
    String -> [NSObject:AnyObject]?
let extractCreationDate:
    [NSObject:AnyObject] -> NSDate?

How does that help us? Well, you can see our pattern of returning an optional, unwrapping it, and returning the next optional in turn. It’s a sequence of operations - a series of tubes, as it were. But how do we connect these tubes together?

bind and Function Composition (14:05)

We connect these tubes using a straightforward, mathematical-oriented idea called composition. We’re going to compose functions together. To do that, we’re going to use a functional tool called bind. Bind - this is where those signatures help - is a function defined like so:

func bind<A, B>(a: A?, f: A -> B?) -> B?
{
    if let x = a {
        return f(x)
    } else {
        return .None
    }
}

We have a first parameter, which is optional, and a second parameter, which is a function. This function takes the first parameter that’s unwrapped already, and returns a value that is optional. By the type signature, you can kind of figure out what this bind function is actually doing. You can assume that if you have an optional A parameter for bind and the function f takes a non-optional A parameter, bind actually unwraps the parameter a before it applies the function. It’s a super simple function that unwrapw the optional and applies the function is a value is there. If it’s not there, we have nothing to do, so we just return nothing. With this very simple function, we can start composing all of our other functions!

Let’s start at the beginning. We have our filePath parameter, which is an optional string, and the fileExists function. We can pass that in as our second parameter. fileExists returns an optional string as well, so we can take the results of the first bind call and pass that in as the first parameter of another bind call. We can then compose that with the function retrieveFileAttributes. We can take this to the next step and use the result of the second bind call as the first parameter of yet another bind call. For this third bind, we can pass in extractCreationDate as our second parameter.

let creationDate: NSDate? =
bind(bind(bind(filePath, fileExists),
retrieveFileAttributes),
extractCreationDate)

By now, I hope you are recognizing the pattern - we’re just nesting functions and putting values from other functions as parameters to use the next function. We’re really just chaining these things together. At the end of these three operations, we actually get a creation date.

The bind Operator >>= (17:01)

However, this is pretty hideous. This is not how I like to code because this code is harder to read than it was before. What I like to use is something like this: the bind operator >>=. We can define this very simply:

func >>=<A, B>(a: A?, f: A -> B?) -> B?
{
    return bind(a, f)
}

Here, we alias this >>= operator to bind. This is how we use the operator:

// no operator 
bind(filePath, fileExists)

// using the operator >>=
filePath >>= fileExists

That might not look like a whole lot, but when you use this operator in our example, our code starts read a little bit better. It’s a little more concise, and it’s a very functional-oriented way to code something.

if let creationDate = filePath >>= fileExists >>=
retrieveFileAttributes >>= extractCreationDate
{
    return creationDate.isBefore(NSDate.oneDayAgo())
}

This isn’t quite the right vocabulary, but I like to think of this bind operator as “goes into”. On the right-hand side, the operand, we have a function. The first value goes into that function, whether it’s optional or not, and it will be unwrapped. Our filePath goes into the fileExists, and that result goes into the retrieveFileAttributes function, which in turn, goes into the extractCreationDate function. We extract creationDate out of the entire series of these operations, all of which need to succeed in order to get that creation date that we want to compare.

We can take this one more step further with creationDate.isBefore. This should be our checkExpired function, where we take our now vlid date and return an optional boolean. In this case, our optional is never really optional, since we’re always going to have true or false, but we ned the type signature to match so that we can pipe it into our bind operator sequence. We end up creating a nice one-line function that does a very simple comparison, which results in this code:

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

We can simply turn this into our return statement. If we somehow happen to fail anywhere along this chain, we’re going to return false by default, or return whatever is actually valid for checkExpired. It turns everything into a very concise statement that says all these things have to happen in sequence. This is how we chain smaller functions together. Here is the end result for our particular function:

func expired(fileURL: NSURL) -> Bool {
    let fileManager = NSFileManager()
    var error : NSError?
	
    let filePath = fileURL.path
    let fileExists : (String) -> (String?) =
    { path in fileManager.fileExistsAtPath(path) ? path : nil }
    let retrieveFileAttributes : (String) -> ([NSObject: AnyObject]?) =
    { path in
        var error: NSError?
        return fileManager.attributesOfItemAtPath(path, error: &error)
    }
    let extractCreationDate : ([NSObject:AnyObject]) -> NSDate? =
    { $0[NSFileModificationDate] as? NSDate }
    let checkExpired: NSDate -> Bool? =
    { $0.isBefore(NSDate.oneDayAgo()) }

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

You might be thinking that this is actually a bigger function, but now it’s composed of smaller functions. We can start extracting these smaller functions out to somewhere else. This can be at some global scope or just in your class scope, but you could start using these as utility functions as it makes sense in your own application.

This is definitely just an example, but what really is important is this last line at the bottom - the meat of what we’re trying to do in this particular function. Having smaller one-line or two-line simple functions makes the code less prone to errors when you’re going through the debugger and trying to figure out what went wrong. For example, it’s hard to say that the attributesOfItemAtPath function failed, for whatever reason. It really makes it easy to pinpoint some of the errors that occur. For instance, maybe one particular function can never fail for certain cases, and you could then start to isolate the problem as you step through the code.

This technique is really well explained in this railway-oriented programming approach, and I highly recommend checking this blog post out.

flatMap, apply, and Reading Functional Operators (21:59)

A quick note on readability, which you might have noticed with the bind operator and the “goes into” operator: readability may pose a problem in functional programming, so I want to introduce you to some of the more common operators that I have seen in the functional world. Some really simples ones are bind (>>=, >>-), flatMap, also known as fmap (<^>, <$>), and apply (<*>).

Here is the code for fmap and its operator <ˆ>. It looks a lot like bind, and in fact, you can define bind in terms of fmap, and vice-versa. These two functions essentially have reversed signatures.

func fmap<A, B>(f: A -> B, a: A?) -> B? {
    if let x = a {
        return f(x)
    } else {
        return .None
    }
}

func <^><A, B>(f: A -> B, a: A?) -> B {
    return fmap(f,a)
}

We also have the apply operator, which says that we might have an optional function. This lets us chain a lot of operations together. This is a simple function that enables us to connect other functions and perform a sequence of operations in a very powerful, concise manner.

func <*><A, B>(f: (A -> B)?, a: A?) -> B? {
    return apply(f, a)
}

func apply<A,B>(f: (A -> B)?, a: A?) -> B? {
    if let x = a, let fx = f {
        return fx(x)
    }
    return .None
}

Argo: Functional JSON Parsing Framework (22:46)

A library that I really enjoy using for JSON parsing is called Argo, by Thoughtbot. It really takes advantage of the functional style to parse JSON, and I really recommend checking this great library out.

Combining Object-Oriented and Functional Programming: Caching (23:21)

All this time, I’ve been talking about functions. But what about objects? Like I said before, we’ve dealt with objects often in our career. So far, they have been the masters of the universe. But in functional programming, they’re more or less on the same level as functions. You could accomplish a lot by combining the two.

One example that I’ve run into recently is caching. A lot of you might have to do that, especially on mobile apps. One thing that you want to do with the cache is retrieve things. Looking at it from a broad perspective, we have a kind of client, a remote data source, and possibly even local stuff. It turns out that you might want to do things a little bit differently when you cache data and get it to the data source.

In an object-oriented way, we might have something like a cache that manages how we switch between one data source to the other. But we can also go one step further and extract our strategy of switching caches into a strategy itself. A strategy pattern is a recommended way to do handle this switching. In this example, we can have a protocol and define our data source to have it fetch an item from one or more sources.

protocol DataSource {
    func fetchItem() -> Int?
}

func retrieveItem<S:DataSource, T>(from: S, or: S) -> T? {
    return from.fetchItem() ?? or.fetchItem()
}

This is a terrible cache because it doesn’t fail if the last one doesn’t succeed. What’s wrong with that function is that it’s not actually a generic retrieve item function, but a very specific one. In Objective-C, I would take this function call and separate out the object instance from from the selector .fetchItem() to make it more dynamic. Because I have two objects, I want to apply the selector to the other one depending on which one succeeds or fails. You can’t do this in Swift without a lot of difficulty, and so we have to invert our thinking:

func retrieve<S: DataSource, T>
    (from: S, or: S, using: S -> T?) -> T?
{
    return using(from) ?? using(or)
}

We instead apply a function to the object to actually call that function on the other object. We have a rerouter function that does this by passing in another function that we can apply to each object. We apply the function to the first one, otherwise it’s applied to the second one. It elegantly turns our callers into something like this:

let localDataSource: DataSource
let remoteDataSource: DataSource
return retrieve(from: localDataSource, or:
    remoteDataSource) { $0.fetchItem() }

We can thus retrieve from one or the other, and then fetch our data using this little tiny function. It consolidates the actual task with a collection of objects that we’re operating on. We can change it even further to result in this code:

protocol DataSourceCacheStrategy {
    func retrieve<T>(from: [DataSource], using: DataSource -> T?) -> T?
}

struct DataSourceCache {
    let strategy: DataSourceCacheStrategy
    let localDataSource: DataSource
    let remoteDataSource: DataSource
	
    func fetch<T>(applyFunction: DataSource -> T?) -> T? {
        let sources = [localDataSource, remoteDataSource]
        return strategy.retrieve(sources, using: applyFunction)
    }
}

We could also change our data source function to take an arbitrary number of data sources, and have any data source that has data just return that value:

struct BasicDataSourceCacheStrategy: DataSourceCacheStrategy {
    func retrieve<T>(from: [DataSource], using: DataSource -> T?) -> T?
    {
        for dataSource in from {
            if let result = using(dataSource) {
                return result
            }
        }
        return nil
    }
}

We can also add a validation step in there to validate our data:

struct MoreFancyDataSourceCacheStrategy: DataSourceCacheStrategy {
    func retrieve<T>(from: [DataSource], using: DataSource -> T?) -> T? {
        let cacheValidation: T? -> Bool = { $0 != nil }
		
        for dataSource in from {
            let result = using(dataSource)
            if cacheValidation(result) {
                return result
            }
        }
        return nil
    }
}

Benefits of Combining OO and Functional Paradigms (27:06)

We can do all these things with our object-oriented approaches. Both functional programming and object-oriented programming are good at encapsulating things. By creating functions composed of smaller functions, you can hide things in your code within functions. These also provide abstraction - by passing functions into other functions, you no longer have to know all the details of your inputs. You only need to specify a certain output and nicely defines those contracts in your code.

Both paradigms have a lot in common. If you follow the good object-oriented principles of design, you will end up at a very similar place. The easiest way to get started with functional programming and merge it with object oriented is to think about using OO in the larger scope of your application design, whether to consolidate and connect things, or describe and model your domains. Use functional programming, at least to start with, in a lot of your functions and your methods, and just try to consolidate a lot of that logic using pipelines.

A lot of times when you want to use functional programming, you should consider whether things change or not - mutable versus immutable. That’s something that you’ll probably see in your own apps as more difficult to change. Objects like Windows change a lot, but you only have one object. However, there are definitely functional-friendly problem domains, especially when handling immutability and concurrency.

Summary (29:03)

I was less interested in programs as algebraic patterns than I was in a clear scheme that could handle a variety of styles of programming.

  • Alan Kay

Object-oriented programming is still useful. As one of the originators of Smalltalk & an early collaborator on Simula, Alan Kay always saw object-oriented programming as a way of simplifying our code. We can still have the best of both worlds by just trying to be pragmatic about how we’re using them.

Q&A (29:33)

Q: How do you handle working with teammates in a functional environment?

Saul: In a functional environment where other team members might not be versed in that, you can work with them by doing things like defining the operation up front and explaining fmap, bind, and apply. An ideal situation for this is pair programming, in which you may sit with them and explain to them how things work. I highly recommend this series of articles, Efficient JSON in Swift (Part 1, Part 2), from the authors of Argo. You can use this to walk your teammates through the process. It’s definitely educational, and there is no way around it. Sometimes, you have to explain things over and over.

Q: Do you hope that Swift will add more of these operator type things as syntactic sugar to Swift by itself?

Saul: I believe the functional operators will become community standards as we see fit to adopt, and Apple’s own implementation is less relevant given how easy it is to define our own operators. Argo, for instance, extracted a lot of these common operators into a smaller sub-library called Runes. I’ve been writing an app using the Runes framework, which is almost literally a framework that just has those bind operators. I’ve been building a little framework for an app, and I’ve got maybe three or four if statements in the entire framework so far just because I’ve extracted them all using this style of programming.

Next Up: iOS Paradigms #6: Swift and the Legacy of Functional Programming

General link arrow white

About the content

This talk was delivered live in June 2015 at AltConf. The video was recorded, produced, and transcribed by Realm, and is published here with the permission of the conference organizers.

Saul Mora

Trained in the mystical and ancient arts of manual memory management, compiler macros and separate header files. Saul Mora is a developer who honors his programming ancestors by using Optional variables in swift on all UIs created from Nib files. Despite being an Objective C neckbeard, Saul has embraced the Swift programming language. Currently, Saul resides in Shanghai China working at 流利说 (Liulishuo) helping Chinese learn English while he is learning 普通话 (mandarin).

4 design patterns for a RESTless mobile integration »

close