Implementing NS_OPTIONS in Swift

Implementing NS_OPTIONS/bitmasks nicely in Swift is a pain. Nate Cook managed to work out that Swift automatically turns your Objective C NS_OPTIONS into a struct, for example:

typedef NS_OPTIONS(NSUInteger, UIViewAutoresizing) {
    UIViewAutoresizingNone                 = 0,
    UIViewAutoresizingFlexibleLeftMargin   = 1 << 0,
    UIViewAutoresizingFlexibleWidth        = 1 << 1,
    UIViewAutoresizingFlexibleRightMargin  = 1 << 2,
    UIViewAutoresizingFlexibleTopMargin    = 1 << 3,
    UIViewAutoresizingFlexibleHeight       = 1 << 4,
    UIViewAutoresizingFlexibleBottomMargin = 1 << 5
};

gets turned into this:

struct UIViewAutoresizing : RawOptionSet {
    init(_ value: UInt)
    var value: UInt
    static var None: UIViewAutoresizing { get }
    static var FlexibleLeftMargin: UIViewAutoresizing { get }
    static var FlexibleWidth: UIViewAutoresizing { get }
    static var FlexibleRightMargin: UIViewAutoresizing { get }
    static var FlexibleTopMargin: UIViewAutoresizing { get }
    static var FlexibleHeight: UIViewAutoresizing { get }
    static var FlexibleBottomMargin: UIViewAutoresizing { get }
}

which most likely has an implementation such as this (all credit to Nate Cook!):

struct MyOptions : RawOptionSet {
    var value: UInt = 0
    init(_ value: UInt) { self.value = value }
    func toRaw() -> UInt { return self.value }
    func getLogicValue() -> Bool { return self.value != 0 }
    static func fromRaw(raw: UInt) -> MyOptions? { return MyOptions(raw) }
    static func fromMask(raw: UInt) -> MyOptions { return MyOptions(raw) }

    static var None: MyOptions          { return MyOptions(0) }
    static var FirstOption: MyOptions   { return MyOptions(1 << 0) }
    static var SecondOption: MyOptions  { return MyOptions(1 << 1) }
    static var ThirdOption: MyOptions   { return MyOptions(1 << 2) }
}

Which is rather ugly to code for every single option set you want. I really hope Apple are going to add a native set type!

I’ve come up with an alternative solution that I think looks a bit nicer and works well in the meantime.

This is what I have in OptionSet.swift:

class OptionSet: RawOptionSet {
    var value: UInt32 = 0
    init(_ value: UInt32) { self.value = value }
    func toRaw() -> UInt32 { return self.value }
    func getLogicValue() -> Bool { return self.value != 0 }
    class func fromRaw<T: OptionSet>(raw: UInt32) -> T? { return T(raw) }
    class func fromMask<T: OptionSet>(raw: UInt32) -> T { return T(raw) }
}

func ^<T: OptionSet>(a: T, b: T) -> T {
    return T(a.value ^ b.value)
}
func |<T: OptionSet>(a: T, b: T) -> T {
    return T(a.value | b.value)
}
@prefix func ~<T: OptionSet>(a: T) -> T {
    return T(~a.value)
}
func &<T: OptionSet>(a: T, b: T) -> T {
    return T(a.value & b.value)
}
@assignment func |=<T: OptionSet>(inout a: T, b: T) {
    a = T(a.value | b.value)
}

Then whenever I want to create an OptionSet I do something like this:

class MyOptions: OptionSet {
    class var None: MyOptions         { return MyOptions(0) }
    class var FirstOption: MyOptions  { return MyOptions(1 << 0) }
    class var SecondOption: MyOptions { return MyOptions(1 << 1) }
    class var ThirdOption: MyOptions  { return MyOptions(1 << 2) }
}

It then works like you’d expect options to behave (test code by Nate Cook):

let singleOption = MyOptions.FirstOption
let multipleOptions = singleOption | .SecondOption
if multipleOptions & .SecondOption {
    println("multipleOptions has SecondOption")
}

let allOptions: MyOptions = .fromMask(7)   // aka .fromMask(0b111)
if allOptions & .ThirdOption {
    println("allOptions has ThirdOption")
}

And if an API needs a UInt32 bitmask (e.g. SKPhysicsBody‘s categoryBitMask) you can just do this:

physicsBody.categoryBitMask = allOptions.toRaw()

Or, for some more fun, we can create a prefix operator * to ‘dereference’ the OptionSet:

operator prefix * {}
@prefix func *<T: OptionSet>(a: T) -> UInt32 {
    return a.toRaw()
}
physicsBody.categoryBitMask = *allOptions

It’s a shame it needs to be an object (as enums/structs don’t have inheritance). It also fails to infer the correct type in some circumstances, for example this:

let allOptions = MyOptions.fromMask(7)
// allOptions is now of type 'OptionSet'

needs to be written as:

let allOptions: MyOptions = .fromMask(7)
// allOptions is now of type 'MyOptions'

If you manage to find a better solution, please let me know :)

Generic Functions in Swift

It’s a bit frustrating that a lot of remnants of Objective C code are appearing in my Swift code. One example is the touchesBegan(withEvent) UIResponder method that takes an NSSet as a parameter. In Xcode’s default SpriteKit project there is the following code:

override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
    /* Called when a touch begins */    
    for touch: AnyObject in touches {
        let location = touch.locationInNode(self)
...

This isn’t very nice, as we have don’t have the benefits of strong typing (that Swift usually provides) for our touch object.

One solution is to write the following:

override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
    /* Called when a touch begins */    
    for touch in touches.allObjects as UITouch[] {
        let location = touch.locationInNode(self)
...

…but with Swift there’s a more fun solution – a generic function!

extension NSSet {
    func arrayContaining<T: AnyObject>(T.Type) -> T[] {
        return self.allObjects as T[]
    }
}

We can now code the following:

override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
    /* Called when a touch begins */    
    for touch in touches.arrayContaining(UITouch) {
        let location = touch.locationInNode(self)
...

Note how we used T.Type as the method argument. If instead we had this:

func arrayContaining<T: AnyObject>(T) -> T[] {

we would need to use it with an instance of UITouch() like this:

touches.arrayContaining(UITouch())

which I don’t think is very pretty. Let me know if you have any other ideas!

Typeclass Encoding in Swift (v3)

Maxwell Swadling wrote an interesting blog post on typeclass encoding in Swift, which was implemented using extensions by @destroyo in his reply blog post.

The challenge was to create a function in Swift that sums an array of any type of number.

First we create a protocol that our number classes will be made to conform to.

protocol Number {
    // 'Self' will become the class conforming to this protocol
    class func zero() -> Self 
    class func sum(a: Self, _ b: Self) -> Self
}

We then add extensions to any required objects that we want to sum.

extension UInt32: Number {
    static func zero() -> UInt32 {
        return 0
    }
    static func sum(a: UInt32, _ b: UInt32) -> UInt32 {
        return a + b
    }
}

extension Int: Number {
    static func zero() -> Int {
        return 0
    }
    static func sum(a: Int, _ b: Int) -> Int {
        return a + b
    }
}

extension Double: Number {
    static func zero() -> Double {
        return 0
    }
    static func sum(a: Double, _ b: Double) -> Double {
        return a + b
    }
}

Here’s our generic function that sums up our arrays:

func sum<T: Number>(array: T[]) -> T {
    return array.reduce(T.zero(), { T.sum($0, $1) })
}

All that’s left is to test it out!

let intArray = [1, 2, 3, 4, 5]
let int32Array = [1, 2, 3, 4, 5]
let doubleArray = [1.1, 2.2, 3.3, 4.4, 5.5]

sum(intArray)    // 15
sum(doubleArray) // 16.5
sum(int32Array)  // 15

EDIT: This is great! But we can do better.

The additive inverse of a real number is its negation, so we can don’t need zero(). There’s also a sum function already included in our number types!

protocol Number {
    class func -(a: Self, b: Self) -> Self
    class func +(a: Self, b: Self) -> Self
}

extension UInt32: Number {}
extension Int: Number {}
extension Double: Number {}

func sum<T: Number>(array: T[]) -> T {
    return array.reduce(array[0] - array[0], { $0 + $1 })
}

let intArray = [1, 2, 3, 4, 5]
let int32Array = [1, 2, 3, 4, 5]
let doubleArray = [1.1, 2.2, 3.3, 4.4, 5.5]

sum(intArray)    // 15
sum(doubleArray) // 16.5
sum(int32Array)  // 15

I wonder if there is a way to remove the need for protocols…