August 20, 2014

Swift, Extensions, Protocols, and Operator overloading

Posted in Uncategorized tagged , , , , , at 4:39 pm by tetontech

I’m working on a Swift matrix manipulation library. Since I want that library to be flexible enough to be used outside of my planned use, a simulation engine, it needs to be able to handle complex numbers. Swift doesn’t have representations for imaginary or complex numbers so I created one. You can get the source for the entire library at my gitHub repo. I call the library SwiftlyComplex. Regardless of why I created the library, there are some Swift programming concepts the library illustrates.

I wanted my representation of complex numbers to be able to have Int and Double type parts but not String or other invalid types. Swift’s implementation of Int and Double have no common base class so I could have done something silly with Swifts Any type and do a bunch of run-time checking or I could have overloaded all my functions to handle all possible combinations of Int and Double. Both of these are bad ideas. For example, if the complex number’s init function had two parameters, one of the real component and one for the imaginary, using the overloading idea I would need to create four init methods that do essentially the same thing, initialize the complex number’s properties. The overloading approach would also make it difficult to declare the complex number’s property types as well. Not a good approach.

So what I did instead was create a BaseNumeric protocol.

protocol BaseNumeric {
    func asDouble() -> Double
    func asInt() -> Int
}
extension Int:BaseNumeric {
    func asDouble() -> Double{
        return Double(self)
    }
    func asInt() -> Int{
    return self
    }
}
extension Double:BaseNumeric {
    func asDouble() -> Double{
        return self
    }
    func asInt() -> Int{
        return Int(self)
    }
}

As you can see, I used this protocol to extend both Int and Double. This allowed me to make one version of all of the complex number’s init and other functions. I also had BaseNumeric add a couple of helper functions to Int and Double to return Double and Int versions of the number. This reduced code duplication in my complex number representation.

BaseNumeric also needed to override the -, +, *, and / operators. They are all very similar. We’ll look at just the override for the – operator.

func - (lhs:BaseNumeric, rhs:BaseNumeric) -> BaseNumeric{
    if lhs is Double || rhs is Double {
        return lhs.asDouble() - rhs.asDouble()
    }
    else{
        return lhs.asInt() - rhs.asInt()
    }
}

This version of the – operator can be placed between two BaseNumeric values, be they Ints, Doubles, or some combination of those, and returns a BaseNumeric. The operator checks the type to see if either BaseNumeric is a Double. If at least one is, then the result is calculated as a Double. If not, the result is calculated and returned as an Int BaseNumeric.

With the BaseNumeric protocol extending both Int and Double, I could now create a struct to represent complex numbers. I called it Complex. Complex implements Swift’s standard Printable protocol so using println() is easy. Implementing Printable meant I needed to add a calculated property of type String called description.

Following this same pattern, I added two custom calculated properties for the common complex number calculations modulus and conjugate. While you may not be dealing with complex numbers yourself, calculated properties in your code will work the same way. They are declared as variables, the return type is declared, the calculation is done, and a value is returned.

import Foundation

struct Complex:Printable{
    var real:BaseNumeric
    var imaginary:BaseNumeric
    
    var description: String{
        return "\(self.real) + \(self.imaginary)i"
    }
    
    var modululus: Double{
        let squaredReal = real * real
        let squaredImaginary = imaginary * imaginary
        return sqrt((squaredImaginary + squaredReal).asDouble())
    }
    
    var conjugate: Complex{
        let inversImaginary = imaginary * -1
        return Complex(real: real, imaginary: inversImaginary)
    }
    
    func combine(rhs:Complex, combineBehavior:(BaseNumeric, BaseNumeric) -> BaseNumeric) -> Complex{
        
        var realPart = combineBehavior(self.real, rhs.real)
        var imaginaryPart = combineBehavior(self.imaginary, rhs.imaginary)
        return Complex(real: realPart, imaginary: imaginaryPart)
    }
}

I also added a combine function. This function allowed me to do both addition and subtraction of my Complex structs with one set of code rather than duplicate the code for both behaviors. To accomplish this, I needed to pass an instance of a Complex to combine with the ‘self’ instance, and a closure, called combineBehavior in the parameter list. The closure would either add or subtract the component pieces of the Complex structs depending on if I wanted addition or subtraction. Calling the combine function in an overloaded version of the + operator shows how to pass the closure.

func +(lhs: Complex, rhs: Complex) -> Complex{
    return lhs.combine(rhs, combineBehavior: {(leftValue:BaseNumeric,rightValue:BaseNumeric) -> BaseNumeric in
        return leftValue + rightValue
        })
}

Since + is defined by Swift as an infix operator, I didn’t need to declare it myself. For a discussion of overloading standard operators and creating custom operators please see my previous posting on that topic.

In addition to the + and – operators, I overloaded the  * and / operators for my Complex class. They calculate the multiplication and division of complex numbers directly since there is not common code between these operators that could be shared.

Now I can create complex numbers using the Complex structure.

     let first = Complex(real: -2, imaginary: 3)
     let second = Complex(real: 1.0, imaginary: 2.0)

and manipulate them using the overloaded operators.

     let difference = first - second
     println("difference: \(difference)")
        
     let product = first * second
     println("product: \(product)")
        
     let quotient = first / second
     println("quotient: \(quotient)")

This makes it much easier to create, manipulate, and display complex numbers.