Implementing NS_OPTIONS in Swift

Update: Nate Cook has created a NS_OPTIONS Bitmask generator which works great. You should also check out Bryn Bellomy’s SwiftBitmask.


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

Update 2: Swift 1.2 introduced a native Set type, which makes the touchesBegan function look like this:

override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
    /* Called when a touch begins */

    for touch in (touches as! Set<UITouch>) {

Good work, Apple! You can read more about the Set type here:
Coding Explorer: Swift Set Type


Update 1: Nate Cook noted that the solution below would cause a runtime error if the set doesn’t contain objects of the desired class. Something like this would be safer:

extension NSSet {
    func arrayContaining<T: AnyObject>(T.Type) -> T[]? {
        return self.allObjects as? T[]
    }
    func arrayContainingOnly<T: AnyObject>(T.Type) -> T[] {
        return self.allObjects.filter() { $0 is T ? true : false } as T[]
    }    
}

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)

Update 6/4/15: updated Swift syntax.


Maxwell Swadling wrote an interesting blog post (web archive) 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
    static func zero() -> Self 
    static 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(), combine: { 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

Update: 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 {
    static func -(a: Self, b: Self) -> Self
    static 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], combine: { $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…