June 17, 2014

Swift, Pipelining, Function Arrays, and Operator Overloading

Posted in Uncategorized tagged , , , , , , , at 9:46 pm by tetontech

In a previous post I showed how to create a pipeline operator, |>, that allows chaining of functions, closures, and mixtures of functions and closures. This posting will overload the pipeline operator so it can be used in a related but different situation.

In functional programming there are known good patterns. Two of these are map and reduce. Reduce applies a single function to an array of values and returns a single value. Summing the values in an array of Ints would be a good example.

Map is similar. It also applies a single function to an array of values. It returns a new array containing one value for each value in the original array but the new array values have been modified by applying the function. An example would be to map a double process to the array [1,2,3] generating and returning the new array [2,4,6].

There is yet another pattern that is common in programming and I use it a lot . It is related to map and reduce. In this situation a single piece of data, be it a Dictionary, Array, Int, String, or any other type, is passed to a series of functions. I haven’t seen a specific name for this type of behavior so I refer to it as spindle (a play on words – fold, spindle, or mutilate).

An example situation that fits the spindle pattern is the validation and application of data received from a source such as a file, a server, the user, etc. In this example I’ll be doing something that is so common in programming that it can seem trivial; validating a user name and password, authenticating the user, and displaying the user interface appropriate for the user. To do this let’s pretend that the data to be validated has come to us as JSON and been converted into a Swift Dictionary having the structure [“uName”:,”pWord”:,”userRole”:].

A few functions to apply in our example would be helpful. These consist of different portions of the validation, authentication, display process. In each function a Tuple is returned consisting of a Dictionary<String,AnyObject> and a String? (String optional) (see my previous post for an explanation of using AnyObject with Dictionaries). The String? is used by the overloaded pipeline operator for error detection and early process termination. The example functions are:

func checkUName(data:Dictionary<String, AnyObject>) 
              -> (Dictionary<String,AnyObject>, String?){  
    if let userNameOptional = data["userName"]? as? String{
            if countElements(userNameOptional.stringByTrimmingCharactersInSet(
                   NSCharacterSet.whitespaceAndNewlineCharacterSet())) > 0{
                return (data, nil)
            }
    }
    return (data, "missing user name")
}
        
func checkPWord(data:Dictionary<String,AnyObject>) 
            -> (Dictionary<String,AnyObject>, String?){
    if let passWordOptional = data["passWord"]? as? String{
        if countElements(passWordOptional.stringByTrimmingCharactersInSet(
                  NSCharacterSet.whitespaceAndNewlineCharacterSet())) > 0{
            return (data, nil)
        }
    }
    return (data, "missing password")
}
      
//var data declares the data Dictionary to be variable rather than fixed.
//This is still functional since data is a copy of 
//the original data Dictionary.  
func isUser(var data:Dictionary<String,AnyObject>) 
             -> (Dictionary<String,AnyObject>, String?){
    // place authentication code here.
    /*
    if authentication passes 
          return (data, nil)
          data["isLoggedIn"] = true
    else
    */
    return (data, "invalid user name or password")
}
        
func showRoleDisplay(data:Dictionary<String,AnyObject>) 
              -> (Dictionary<String,AnyObject>, String?){
    // based on data["userRole"] show a view that matches the users role.
    return (data, nil)
}

For this example we create an Array called login that represents the entire process by listing the functions in the order we want them executed.

var login = [checkUName, checkPWord, isUser, showRoleDisplay];

A Dictionary for use in our example is also created.

var user:Dictionary<String,AnyObject> = ["userName":"sue", 
                        "passWord":"gr4583rt!", "userRole":14]

Using the pipeline operator we will see below, the code to apply login to the user Dictionary is

let (aResult, errorMessage) = login|>user

This line of code reads “Let a tuple be assigned the result of attempting to login a user.” You could also think of it as “Apply login to user and assign the result to a Tuple.” Either way you view the line of code, it seems to read well due to the operator.

So what does the code for the overloaded pipeline operator, |>, look like?

Since we declared the operator in a previous post and are using the same project we do not need to redeclare the operator. The code to overload it is

1 func |> <T>(left: Array<(T) -> (T, String?)>, var right: T ) -> (T, String?){
2    for function in left{
3        let (partialResult,message) = function(right)
4        if message != nil{
5            return (partialResult, message)
6        }
7        right = partialResult
8    }
9    return (right, nil)
10}

Operators are functions so the first line includes the func keyword, the name of the operator, two parameters, and a return of a tuple that includes a String optional. The first parameter, left, is an Array of functions that accept any type T and return a Tuple consisting of that type T and a String optional. The second operator, right, is a variable of the same type T.

Line 2 of the operator iterates over each of the functions in the left parameter. Each function is then called on line 3 and its returned result is checked on line 4. If an error message has been received it, along with the object of type T, partialResult, is returned to break the loop and early terminate the execution of the array of functions.

Line 7 updates the result that will be passed to any subsequent functions called or returned as part of line 9.

This operator can also be used with closures since functions are named closures in Swift.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: