https://www.objc.io/books/functional-swift/

Functional programming in Swift

James Rochabrun
5 min readNov 18, 2018

--

If you are an iOS developer you may hear about functional programming in Swift, but what is for real Functional programming? From Wiki

In computer science, functional programming is a programming paradigm — a style of building the structure and elements of computer programs — that treats computation as the evaluation of mathematical functions and avoids changing-state and mutable data.

It is not easy to give a straightforward explanation about this, however, think about it as instead of building a program in a sequence of assignments and function calls, emphasize it in repeatedly break it in smaller pieces that can be assembled using function application to define a complete program taking careful treatment of the state.

How to start thinking Functionally?

Functions in Swift and many other languages are first class citizens (or first class values), this means that functions are types, this allows to treat them as variables, pass them in function arguments and even functions can return other functions, a function that returns a function? This may not make sense at the beginning but it can help create cleaner and more modular programs.

Before moving forward I want to make a disclaimer, this post was written using as reference the Functional Swift programming book which I highly recommend if you are a Swift engineer. The following implementation is on its chapter 3, I did add some refactoring to improve usability and also updated it for Swift 4.2.

On this implementation, we will use high order functions to write a small functional wrapper around Core Image to easily apply chain filters in a CIImage.

Let’s start by creating a function type…..

typealias Filter = (CIImage) -> CIImage?

The Filter type is just a function that takes a CIImage as a parameter and returns also a CIImage.

Functional programming in Swift also emphasize the use of enums in our programs so that’s what we are going to do now, we are going to have an enum with associated values that will return a filter based on each case….

enum FilterType {    case gaussianBlur(_ image: CIImage, _ radius: Double)    case colorGenerator(_ color: CIColor)    case compositeSourceOver(_ overlay: CIImage, image: CIImage)    var filter: CIFilter? {        switch self {        case .gaussianBlur(let image, let radius):            let parameters:  [String : Any] = [                kCIInputRadiusKey: radius,                kCIInputImageKey: image            ]            return CIFilter(name: "CIGaussianBlur", parameters: parameters)        case .colorGenerator(let color):            let parameters: [String: Any] = [                kCIInputColorKey: color            ]            return CIFilter(name: "CIConstantColorGenerator", parameters: parameters)        case .compositeSourceOver(let overlay, let image):            let parameters: [String: Any] = [                kCIInputBackgroundImageKey: image,                kCIInputImageKey: overlay            ]            return CIFilter(name: "CISourceOverCompositing", parameters: parameters)        }    }}

This enum not only will help us improve readability at the time of consumption but also will help us avoid handling those strings names everywhere when creating filters which can end in unexpected bugs if we misspell it by mistake.

Now we can start defining functions that build specific filters, we will use our enum with associated values to pass the specific parameters for each filter and construct a value of type Filter and return it, we will create a struct for this wrapper.

struct FilterManagerAPI {    func blur(radius: Double) -> Filter {        return { image in            return FilterType.gaussianBlur(image, radius).filter?.outputImage        }    }    func colorGenerator(color: UIColor) -> Filter {        return { _ in            let inputColor = CIColor(color: color)            return FilterType.colorGenerator(inputColor).filter?.outputImage        }    }    func colorOverlay(color: UIColor) -> Filter {        return { image in            guard let overlay =  self.colorGenerator(color: color)(image),                let compositeIamge = self.compositeSourceOver(overlay: overlay)(image) else {                    return nil            }            return compositeIamge        }    }    func compositeSourceOver(overlay: CIImage) -> Filter {        return { image in            let filter = FilterType.compositeSourceOver(overlay, image: image).filter            let cropRect = image.extent            return filter?.outputImage?.cropped(to: cropRect)        }    }
}

These functions returns function types and if you wonder how you will use them lets see an example…

guard let inputImage = CIImage(image: someImage) else { return }
let overLayColor = colorLiteral(red: 0.3647058904, green: 0.06666667014, blue: 0.9686274529, alpha: 0.1143877414)
if let blurredImage = filterAPI.blur(radius: 3.0)(inputImage),
let outputImage = filterAPI.colorOverlay(color: overLayColor)(blurredImage) {
// do something with the outputImage
}

The blur function takes as a parameter a double it returns a function of type Filter which takes a CIImage as a parameter and returns a CIImage then the colorOverlay does the same taking a color as a parameter instead.

A difference of Imperative programming, functional programming takes a Declarative approach, a good example of the difference between Imperative and Declarative is writing a for loop instead of using the map function where the second one is declarative coding.

Sometimes this may make some code a bit hard to read like in the functions above, to help with this we can apply function composition to make this more readable, let's add a new function to apply 2 filters…

// function composition    func composeFilters(filter1: @escaping Filter, filter2: @escaping Filter) -> Filter {        return { img in            guard let firstFilteredImage = filter1(img) else { return nil }            return filter2(firstFilteredImage)        }    }

Now you can call it like…

guard let inputImage = CIImage(image: someImage) else { return }

let outputImage = filterAPI.composeFilters(filter1: filterAPI.blur(radius: blurRadius),
filter2: filterAPI.colorOverlay(color: overLayColor))(inputImage)
// Do something with the outputImage

A bit more readable, If you are not familiar with Core Image and how filters work no worries, you just need an input image and apply one or a chain of filters to it and get an image output, and this is what this function does it applies filter 1 and filter 2 to inputImage and return an output, still we can go a bit further and use an infix operator to declare this even better…

infix operator >>>precedencegroup ExponentiationPrecedence {    associativity: left}
func >>>(filter1: @escaping Filter, filter2: @escaping Filter) -> Filter { return { img in guard let firstFilteredImage = filter1(img) else { return nil } return filter2(firstFilteredImage) }}

Now we can chain our filters like this…

let overLayColor =  colorLiteral(red: 0.3647058904, green: 0.06666667014, blue: 0.9686274529, alpha: 0.1143877414) guard let inputImage = CIImage(image: someImage) else { return } let filter = filterAPI.blur(radius: 0.3) >>> filterAPI.colorOverlay(color: overLayColor) guard let outputImage = filter(inputImage) else { return }

Here we create a nice chain of Filter types and use it to get an output image, there you have it functional programming is all over the Swift Language and I hope this post helps you understand it a bit better.

Here is the full implementation for this post.

This story is published in Noteworthy, where 10,000+ readers come every day to learn about the people & ideas shaping the products we love.

Follow our publication to see more product & design stories featured by the Journal team.

--

--