Custom Operators

It feels great to see my first Swift app in the App Store, but now it’s time to face the mountain of dicey code I wrote to get it out there.

Functional Thinking

Making the transition to Swift means paying closer attention to functional paradigms. A basic feature of functional programming languages is that functions become first-class citizens - they can be attached to classes and structs, returned from functions, and passed from function to function.

This feature enables us to work at a high level. Instead of looping through a list and performing some operation on each element, we can simply call a function.

The Problem

In the context of my app, data being returned from the API was being parsed into dictionaries of the form:

Dictionary<String,[CGFloat]>

In several places, I needed to loop through a dictionary like this, grab the last CGFloat from each array, and ultimately return a new array of the form [CGFloat].

My Regrettable Hack

My initial pass at this reflects an object-oriented approach: looping, performing an action, constructing a new object, and returning it:

    private func values(nameValueMap:Dictionary<String,[CGFloat]>) -> [String] {

        var values:[CGFloat] = [CGFloat]()

        for nameValuePair in nameValueMap {
            let (name, data) = nameValuePair
            var roundedValue:CGFloat?
            if ( data.last != nil ) {
                roundedValue = round(data.last! * 10.0) / 10.0
            }
            values.append(roundedValue)
        }
        
        return values
    }

A Functional Solution

My second pass wrapped the operation being performed on each element of the dictionary in its own function.

private func value(values:[CGFloat]) -> CGFloat {
    var roundedValue:CGFloat?

    if let unwrappedValue:CGFloat = values.last {
        roundedValue = round(unwrappedValue * 10.0) / 10.0
    }

    return roundedValue
}

With value(values:[CGFloat]) -> CGFloat in hand, the code from my first pass can be squashed down to a couple of succinct function calls:

private func values(nameValueMap:Dictionary<String,[CGFloat]>) -> [String] {
    return nameValueMap.map({ values in
        value(values)
    })
}

One Step Further

I was feeling good about the functional solution to my initial problem, but the fact remained that I needed to perform this same operation in multiple places across the codebase.

Writing a custom postfix operator saved me the trouble duplicating this code, and made its invokation even more succicnt.

To do this, I created a new Swift file and simply added a public function: ``` postfix operator ◊ {} public postfix func ◊ (choiceValues:[CGFloat]) -> String { var roundedValue:CGFloat?

if let unwrappedValue:CGFloat = values.last {
    roundedValue = round(unwrappedValue * 10.0) / 10.0
}

return roundedValue } ``` 

The postfix operator may seem a little cryptic, but the benefits are worth it. Using , the looping mess that I initially faced the prospect of mainting is reduced to:

private func values(nameValueMap:Dictionary<String,[CGFloat]>) -> [String] {
    return nameValueMap.map({ values in
        values◊
    })
}

This implementation has it all. The higher-order function map and our own operator mask the complexity of looping and filtering behind a couple of easy calls. The management of internal state and the manual checking individual elements are, figuratively speaking, swept under the rug. Ultimately, although the functional solution is not always the most concise or performant, this example makes clear that there is much to gain from revisiting places where a functional solution can reduce outward complexity and enable us to attack problems from a high conceptual level.