Functional Programming in Swift

There were a lot of discussions recently about functional nature of Swift. People are arguing whether Swift is a functional language, can we do functional programming in Swift etc.

Swift is certainly not a functional language, but doing functional programming doesn’t require a pure functional language. No matter what language we use, programming in a functional style can provide lots of benefits and should be used when convenient. To answer can we easily do functional programming in Swift, we first need to define what functional programming is.

image1_large

Functional Programming Definition

There is no single and precise definition of functional programming, but maybe the best way is to do so in terms of goals the paradigm aims to achieve and tools it uses. The main high level goals for a functional program are modularity, careful treatment of mutable state and in some functional languages extensive usage of types to produce safe, easy to maintain, easy to test and performant code. Using simple functions and rich types we increase probability to catch bugs in compile time rather than in production. Functional programming is a declarative programming style that treats computation as the evaluation of mathematical functions. Using these pure functions as main building blocks avoids mutable state, especially shared mutable state. Functions are primary units of abstraction and base building blocks of a program, in contrast to object oriented paradigm where we have objects as main building blocks. Essence of functional programming is minimising and controlling side effects. This is achieved by using pure functions and value types as data those functions transform. In functional languages functions are not just transformations on some data represented with value types, they are first class type itself, so they can be used as inputs and outputs in other functions, the same way as any other type is used.

Paradigms of Swift

Looking at what Swift natively supports in terms of programming concepts, it is certainly not anywhere close to pure functional languages like Haskell, but it is not just an object oriented language either. It interoperates with Objective-C nicely, but it is very different kind of a language, not only because of fundamental difference of strictly typed versus dynamically typed languages but also it is a lot different in its core philosophy about how to write software for safety, maintainability and performance. It is influenced by many different languages and functional languages were one particularly important source of inspiration for Swift.

We can write pure object oriented code in Swift that is very similar to Objective-C code but what we get then is really just Objective-C in Swift syntax. In this kind of code we don’t use at least a half of the Swift’s power. Emulating Objective-C code in Swift syntax can even have just opposite effect on achieving Swift goals, e.g. by overusing classes where Swift idiomatic should be structs and other value types we can significantly decrease performance in computationally intensive code.

Swift as language, compiler that is behind its power, and conventions that probably will be as important aspect for Swift programming as it was for Objective-C and Cocoa, are all in rapid development still, but core philosophy of Swift is pretty clear.

It is obvious that is not functional nor just object oriented, it is not religious at all. This is very pragmatic language that takes the best ideas from other programming languages and applies them in a coherent way.
Swift makes core aspects of functional programming as a corner stones of its vision of how to write safe, easy to maintain and fast code. Immutability is not just a convention for collections anymore, everything in Swift should be immutable by default. We declare all our variables with let keyword, and only when really necessary by semantics of the variable we change it to a var. Objects are not so prevalent in our code anymore. Most of types in Swift are values: all number types, String, tuples, powerful enums and structs, arrays, sets and dictionaries. Only reference types are classes and functions. Function type in Swift is a first class type. All of these makes Swift a multi-paradigm language that makes both object oriented and functional concepts equally natural to use.

In next few paragraphs we will explore in more detail some of those functional features of Swift.

image2

Immutability

Immutability is a big theme in functional languages and in Swift as functionally inspired language also. In functional programming, data structures are immutable by default, so functions cannot modify the state of the program. In Swift as multi-paradigm language we can easily create mutable data structures and we should do it sometimes, e.g. when dealing with object oriented part of the language, but avoiding mutable state is so useful thing to do that Swift strongly encourages this approach providing an easy way to do so with simple let keyword and rich value types.
Benefits of using immutability go from having cleaner code with less possibility for bugs, much easier dealing with concurrency to more opportunities for compiler to optimize the code for performance.
Careful treatment of let versus var also makes intent much cleaner. If it is something declared with var we are sure it supposed for this value to change and it becomes less probable to make bugs related to handling changing state.

Collection types are especially important in context of immutably. Even in Objective-C we prefer using immutable collections, e.g. NSArray instead of NSMutableArray. Swift makes this easier by having single type for both mutable and immutable version using let or var declarations to distinguish between the two in the same way as we do it for simple types. Collections in Swift can contain instances of any type in contrast to Objective-C collections that can hold only objects.

Value Types

In most languages we have at least some simple value types like numbers, simple enums and structs. Value types are great because they are copied on assignment so they have always just one owner what makes code easier to reason about and generally safer because of no dependencies to other parts of the program. They are in general very inert, isolated and interchangeable making our code cleaner, simpler, so a bit safer, especially in multithreaded environment, more composable and reusable, and much easier to test. They usually provide performance gains also.

We use value types in Objective-C too, however they are usually so simple that we can’t use them very often and as versatile as we can use class types, we even can’t put them in collections without wrapping in a object what defeats most of value type purpose. In Swift we can use them the same way as any other type, and in fact all collection types are value types also. In functional languages value types are what we use for storing data on which functions operate producing other values as results. Swift with its rich and powerful set of value types enables us to use them much more often than it is usual in object oriented languages.

Objects in Swift code are most commonly those that we get returned from object oriented frameworks or those we inherit from there, like UIView and UIViewController objects. Our custom types should be classes only if we really need some class specific features like inheritance, although we always prefer composition over inheritance even in Objective-C, or the type represents something that semantically should have identity so that it really should be passed by reference rather than by value. In all other cases what we would make as classes in Objective-C in Swift should be a struct because structs in Swift are almost as expressive as classes but have all value type benefits. Similar to classes they can conform to protocols, define methods, can be extended and of course they have initializers, where one default initializer we get for free.

Properly using structs instead of classes can lead not only to much safer and easier to maintain code, but also to performance gains in computationally intensive parts of the program.

Enums are especially powerful in Swift because cases can have associated values. This kind of types known as sum types are common in functional languages. Some of the core language features like optionals are implemented as enum and we can use them to implement other equally elegant patterns, e.g. in various error handling situation we can define a generic Result type with Success with associated value and Failure with another, maybe error message, or some more general state machine type where we have few mutually exclusive states an object can be in, maybe have some associated value in a particular state, and everything related to transitions between the states can be encapsulated in methods defined on enum. This powerful value type can be used inside an object as key for simplifying its internal structure by decoupling its state from its value having this way a great blend of functional and object oriented features.

Even simple value types as number types are more useful in Swift than in Objective-C because we can extend them with some custom methods.

First Class Functions

Functions are first class type in Swift. This means that in Swift, similarly to what we have in functional languages, functions are data the same way as values and instances of classes are. There is no difference between function type, e.g. (Int, Int) -> Int and any other type e.g. Int. Value of first type is a function that takes two integers and returns an integer, value of second type is just an integer. Both can be stored in a simple variable, or added to a collection, or passed to or returned from another function. They can be defined or stored inside a variable both on global scope or inside an object as a property or inside a method stored in a local variable. A function can even have defined another inner functions inside its body if we have a more complicated logic that should be divided into simpler private components. In Swift we can also define unnamed functions called closures that behave in the same way as named function with addition that they capture variables in enclosing lexical scope where they are defined. They are similar to blocks in Objective-C, but with much simpler syntax, consistent with syntax for named functions, so we can use them even more than we would use blocks. Functions and closures can be used interchangeably. Operators in Swift are actually functions also, just with different calling syntax, augmenting the fact that a function is one of the main building blocks of Swift as language. Swift also supports generic programming paradigm and this can be nicely combined with functional approaches.

Pure Functions

When talking about functions in functional languages we actually always mean a pure functions, i.e. mathematical functions, those that just transform an input value into an output value without affecting any other part of the program or that can be affected by any other part of the program – the function doesn’t have side effects. Because the function is completely isolated from all other parts of the program and will always return the same output for the same input it is very testable, the code itself is very reusable and can be composed to form more complex functions, and this provides opportunities for optimization for performance e.g. with some kind of caching mechanism if we expect repeated calls with the same values, maybe in a recursion. It also enables laziness, we can evaluate functions only when output is needed, there is no order dependencies, and this way the code is easier to parallelize. If we apply these concepts when making functions in Swift we can get the same benefits as in functional languages. In strictly typed functional languages great emphasizes is made on carefully choosing types for arguments and return values. Name of the function should be very clear about this single and simple transformation it defines, but input and output types should be clear also about what they represent, that often even without looking at function name, we can know what function does only looking at types. To achieve so clear and modular code we should make functions simple, types expressive, and use functions composition for building the program in a declarative manner.

In a multi-paradigm language is not always achievable or desirable to have pure functions, especially for functions defined as an object methods, but it is good goal to strive to, because it is much easier to reason about them and they are generally much more useful than non-pure functions if we want to compose them to make more complex programs.

Function Chaining

In object oriented languages objects interaction is what makes a complete program that behaves in a way to produce desired effects. In functional program it is series of functions chained to produce desired output. We chain method calls in object oriented code also, but in functional languages it is just more prevalent and much easier to do with pure functions. We can always chain functions in whatever order we need, if types match, and can easily reason about this code, easy to debug, easy to test.

Lets say we have defined a simple type, e.g. struct Person:

struct Student {
  let ID: Int
  let name: String
  let grade: Int
}

We also have few simple functions that transform arrays of these structs: filterOutFailed, sortByGrade, formatForPrint, and a function that joins array of strings by a comma joinByComma.

Say we have an array of Students called students and we want to print comma separated list of students with grade greater than 50 of maximum 100 with their names and grades, sorted by grade.

This is just a chain of functions application:

let result = joinByComma(formatForPrint(sortByGrade(filterOutFailed(students))))

We need to read it from inside to out to see flow of transformations, and if there are lots chained functions, it becomes both hard to read and hard to change.

To make chaining or pipelining easy, functional languages usually have an operator for this, often called pipe operator, that replaces f(g(x)) with something like x >| g |> f. This is forward pipe operator that applies function g on a variable x, then function f on the result of previous function application.

Swift standard library doesn’t define any pipe operator, but we can define it as a custom operator ourselves and use the same way we would in any functional language. There are already few good open source functional libraries that define these kind of standard operators.

This is how we could define forward pipe:

infix operator |> { associativity left precedence 80}
func |> <T, U>(value: T, function: (T -> U)) -> U {
  return function(value)
}

And now instead of usual nested function calls we have syntax similar to what is used in functional languages

let result = students |> filterOutFailed |> sortByGrade |> formatForPrint |> joinByComma

 

image3

Function Composition

In functional languages we always want to have functions made as simple building blocks for our program. This makes function composition central part of functional programming. Too simple functions without ability to compose them wouldn’t be very useful because chaining too many too simple functions, often repeatedly in same order, doesn’t lead to readable and maintainable code. If we want to add a function in a chain or change order to get different behavior we would need to do this in all places we use this combination of functions. Making more complex functions by composing them in the same way like mathematical functions composition works enables us to keep our code simple, easy to read and easy to change.

Swift currently doesn’t provide function composition operator so we can define it ourselves like this:

infix operator >> { associativity left }
func >> <T1, T2, T3> (left: (T1)->T2, right: (T2)->T3) -> (T1)->T3 {
  return { (t1: T1) -> T3 in return right(left(t1)) }
}

It enables as to compose functions once and apply the composition multiple times to not repeat functions chaining in every place, e.g. if we need formatted students list in various places of the program we can define new function formatPassedStudents as s composition:

let formatPassedStudents = filterOutFailed >> sortByGrade >> formatForPrint >> joinByComma

Then every time we need to apply this on an array of students we do it just as any other function:

let passedStudentsListing = formatPassedStudents(students)

Currying and Partial Application

Currying is process of transforming a function that takes multiple arguments into a function that takes single argument and returns another function that takes remaining arguments. This way we can transform any function of multiple arguments into chain of multiple functions with single argument. Swift natively supports currying.

Say we have a more general type of join function than one from the previous example that joins by comma, a function that can join by any given separator declared like this

func joinBy(separator: String, array: [String]) -> String

This is an ordinary declaration of a function that takes two arguments but Swift enables as to declare it also in a slightly different way and what it treats like a curried function:

func joinBy(separator: String)(array: [String]) -> String

If we declare a function this way we call it with first argument and return value is function of type [String] – > String. We can use this to partially apply function to get new function with a concrete joining separator baked in, e.g. previously mentioned joinByComma is just partially applied curried function:

let joinByComma = joinBy(“,”)

The same way we could make joinByNewLine and use it for another students grade report functions composition:

let joinByNewLine = joinBy(“\n”)
let formatPassedForVerticalPrint = filterOutFailed >> sortByGrade >> formatForPrint >> joinByNewLine
let verticalListing = formatPassedStudentsForVerticalPrint(students)

To avoid duplicating function definitions for both non-curried and curried version, if we need both, we can make a generic function that curries a given function.

func curry<A, B, R>(f: (A, B) -> R) -> A -> B -> R {
  return { a in { b in f(a, b) }  }
}

Function curry can curry any function with two arguments. In similar way we can define overloads for any number of arguments.

Now if we already have non-curried version we don’t need to use native syntax for defining a curried version of the same function, instead we can make one from the existing function:

let curriedJoinBy = curry(joinBy)

And having this curried version joinByNewLine would be defined as

let joinByNewLine = curriedJoinBy(“\n")

Higher Order Functions

As said previously, functions in Swift are first class citizens. Function can be passed to another function as argument or returned from it. These kind of functions that take or return other functions are known as higher order functions and they are central part of functional programming. We don’t make functions and curried functions that we vary in partial applications to get even more various simple functions just for building compositions from all of these components to finally apply them on some simple values or collections of values. The real power comes when we pass them into various higher order functions. There are three powerful generic higher order functions we have in functional languages and in Swift also, with their standard names as filter, map reduce. These functions do generic transformations on sequences: filtering elements by predicate, mapping elements to another array by applying some transformation on each element, reducing a sequence to a single value applying some combine functions to each element and a result initialized with a starting value, e.g. summing all elements of number sequence where initial value is zero.

These common higher order functions are defined as methods on CollectionType since Swift 2.0. In Swift 1.0. syntax that we use here just for an illustration of functional concepts they really were defined as global functions in standard library, similar to what we have in functional languages.

Filter

Filter function in functional languages usually takes two arguments, first is an argument of some sequence type, second is a predicate function. Returning value is a sequence of elements which pass this condition.

Say we have a function that checks if a student is passed.

func passed(student: Student) -> Bool {
  return student.grade > 50;
}

We can now use filter function to get students passed from array of students:

filter(students, passed)

This one line of code could be the whole implementation of function filterOutFailed we used in first example.

Map

Map function in functional languages or in Swift 1.0 syntax takes two arguments, first is an argument of a sequence type, second is a function that takes an element from this sequence and transforms it in some way. Returning value is an array of those transformations.

Say we are printing student’s results in format “Name (Grade)”, the whole implementation of
function formatForPrint could be one line of code

map(students, formatStudentForPrint)

where formatStudentForPrint does formatting one student data, or because it is too simple formatting function we could use here a closure instead of another named function.

map(students) {"\($0.name) (\($0.grade))”}

We use here trailing closures syntax to have it more readable. Struct and other value types can have methods, computed properties etc., so in this case probably the most natural thing would be to have a computed property called description defined on Student struct so this can be even simpler:

map(students) {$0.description}

Reduce

Reduce function is usually defined to take three arguments, as first an argument of a sequence type, second as an initial value of a type from which we are building result, third as a function that takes an argument of result type and an argument of sequence element type and it combines current result with an element from the sequence in some way to get a value of result type. Returning value is a result of combine function applied sequentially on all elements. If it were numbers, initial value 0, and combine function +, result would be sum of all elements from the sequence, e.g.

let numbers = [Int](0...100)
let sum = reduce(numbers, 0, +)

First line initializes an array with all Int numbers from 0 to 100, second line calculates a sum of these numbers. Here we use the fact that operators in Swift are functions. It uses here an overload of type (Int, Int) -> Int.

Reduce is a quite powerful. Whenever we do some transformation of a sequence of values that collapses it into a single value it usually can be easily expressed with reduce, so we certainly could implement our joinBy function using reduce.

func joinBy(separator: String, array: [String]) -> String {
  return reduce(array, "") { $0 == "" ? $1 : $0 + separator + $1}
}

In function body we just append separator and an element of array to the previous result, started with empty string, omitting separator on the very beginning.

For completeness lets also define our sortByGrade function we use in the example

func sortByGrade(students: [Student]) -> [Student] {
  return sorted(students) { $0.grade < $1.grade}
}

We use a function sorted, that we define to take an sequence type and a function that takes two arguments of sequence element’s type and that returns Bool with semantics is ordered before. This was actually a part of standard library in Swift 1.0. In Swift 2.0. we have sort method defined on CollectionType so we could use it that way also, and if we make our Student struct conform to Comparable protocol, with < implemented to compare grades, we could make it even simpler.

func sortByGrade(students: [Student]) -> [Student] {
  return students.sort(<)
}

In our simple example all functions had just one simple line of code but the same concepts apply to an arbitrary complex data transformations. We could have a more complex functions that are composed to make even more complex transformations, that can be composed further to even more complex etc. The code stays declarative the same as in simple example. If we put these functions as arguments in filter, map and reduce we get simple to read and maintain but powerful parts of code. One of the most common things we see even in object oriented code are arrays of model objects that we filter in some ways in various parts of program, usually transform in some ways, and maybe do an aggregation into final information we show to the user. Every such arrays-related part of a program can be replaced with a chain of filter, map and reduce that takes more or less complex functions as inputs.

If we do simple transformations we even don’t need to define explicit functions, we can pass around closures, use trailing closures syntax, and because Swift defines filter, map and reduce as methods on CollectionType we can just chain methods on collection types with usual dot syntax even without need for pipe operator we ported from functional languages here for illustration of functional concepts.

Say we have a trivial example similar to dealing with array of Ints.

let numbers = [3, 1, 12, 9, 11, 7, 19, 16, 13, 8]

If we want e.g. to calculate a sum of squares of all even numbers in this array we see that this is just a filter that gets even numbers, chaining a map that makes squares and we finally reduce it to a sum.
Because it is all too simple we don’t define named functions, don’t use pipe operator, just use standard library version of filter, map and reduce with usual method chaining and even simplified with trailing closures syntax.

let sum = numbers.filter{$0 % 2 == 0}.map{$0*$0}.reduce(0, combine: +)

If it gets just a little more complex it is usually best to define functions, and this would be more in a functional style, but Swift provides us with different ways of doing things, to use what is the most convenient in a particular case.

Lazy Evaluation

Laziness is important concept in many functional languages because they work with lists of data all the time. Functional program is made of functions that transforms data. For both better program modularity through separation of concerns and performance reasons, we need an ability to delay computation until necessary. This eliminates needless computations, reduces memory footprint by avoiding to keep in memory huge collections of data and allows interesting abstractions as infinite data structures that are often used in functional languages. Swift provides a simple way to use lazy evaluation even in object oriented parts of a program with lazy keyword that we use to lazy initialize an object’s property.

For functional parts of a program more important is lazy function that turns an ordinary CollectionType into a lazy collection. If we perform an expensive operation on elements of this collection but later happened to use only some of elements, it is better to actually perform the operation only on these necessary elements lazily.

let lotsOfNumbers = 1...1_000_000
let result = lotsOfNumbers.lazy.map(expensiveTransformation)
let combinedByFiveRule = result[5] + result[55] + result[555] + result[5555] + result[55555]

In this part of program we actually computed just five necessary operations instead of a million expensive operations.

image4

Conclusion

We have seen few examples how Swift makes using functional concepts easy, as natural parts of the language, having even functions currying as a language feature, how it encourages immutability, value types usage, working with functions as first class types and how we can apply some simple but powerful concepts like filter, map and reduce to simplify usual use cases, as dealing with lists of data, that we have in every program. Every Swift programmer can apply these basic concepts in his everyday code and it can stimulate curiosity to learn further about deeper functional concepts that can be implemented in Swift as easily, building upon native language concepts.

  • Pingback: 2 – Functional Programming in Swift()

  • gliheng

    Very nice post, thank you!

  • Marketa Hlavon

    Thank-you, very comprehensive post for a person who understands some programming basics but has never used Swift before

  • Pingback: Introduction to Functional Reactive Programming – UIBlog()

  • lihy70

    Very good post. Added to my favors

  • Pingback: Functional Programming in Swift – iamkei()

  • Mike Ormsby

    Danijel, I just stumbled across your article. Thank you so much. I really like the way you explain complex issues simply without a lot of jargon. The article cleared up some misunderstandings for me. I think it’s a good read even for people who aren’t currently using Swift.

  • Rahul Panchal

    Thanks you so much..its very well written..:)

  • Pingback: testing()

  • sridharcse

    Awesome post! Thanks for sharing!