Optionals and if-let

Natasha posted a article a little over a week ago: http://natashatherobot.com/swift-unused-optional-value/. I agree with her initial feelings, "This immediately stood out as "wrong" to me."

Basically she was talking about this:

var someOptionalVar: String? = "something there"

if someOptionalVar != nil {
    // just need to check for the presence of a value
}

I don't like this. It just doesn't feel semantically correct. The optional is not nil, it specifically has a value of None. I've never liked this syntax; I've talked about it before – thankfully the bool comparison has been lost, but the nil check still sits wrong with me.

Another example:

let f‚ÇÄ: Bool? = true
let f‚ÇÅ: Bool? = false
let f‚ÇÇ: Bool? = nil

let fn = [ (f‚ÇÄ, "f‚ÇÄ"), (f‚ÇÅ, "f‚ÇÅ"), (f‚ÇÇ, "f‚ÇÇ")]

for (f, label) in fn {
    if f == nil {
        println("\(label) has no value")
    }
    if f != nil {
        println("\(label) has a value")
    }

    if let fv = f {
        println("\(label) = \(fv)")
    }
    else {
        println("\(label) = nil")
    }

    switch (f) {
    case .Some(_):
        println("\(label) has a value.")

    case .None:
        println("\(label) has no value")
    }
}

It's a bit annoying that we have so many ways to check for the presence of a value in an optional. I find languages that have multiple ways of achieving the same thing end up being confusing, especially as more features get added. It's unnecessary complexity that adds over time. Natasha already pointed out the multiple discussions of people doing it different ways.

I also prefer a different way:

func hasValue<T>(value: T?) -> Bool {
    switch (value) {
    case .Some(_): return true
    case .None: return false
    }
}

for (f, label) in fn {
    if hasValue(f) {
        println("\(label) has a value")
    }
    if !hasValue(f) {
        println("\(label) has no value")
    }
}

There is no ambiguity here, there is not transparent conversion between nil and .None, and most importantly to me, the code is always extremely obvious.

Optionals and if-let

Prototyping Practical FRP

A few days ago I started brainstorming how we might go about handling input in a way that actually satisfies the continuous and temporal nature of FRP behaviors. Today, let’ take a deeper dive into one possible implementation.

Understanding the Problem

The problem can essentially be broken down into the following goals:

  1. Storage of historical input data
  2. Efficient interpolation between discrete inputs

For input handling, there are two basic types: digital and analog. The digital input is on or off, and the analog input is a value that ranges between two min and max values for the input. However, since all of our input is made up of discreet inputs, the problem is nearly identical.

Here is a sample scatter-plot graph of a keypress:

   │                                                              
 1 ┤    ▪           ▪     ▪       ▪             ▪                 
   │                                                              
   │                                                              
 0 └────────▪──────────▪──────▪───────────▪──────────▪───────▶  t 

Each of the represent an actual input change for the button on the time. Of course, the problem with this plot above is that there is no f(t) that results in a value for every value of t. We need to interpolate that graph:

   │                                                              
 1 ┼────▪───┐       ▪──┐  ▪───┐   ▪───────┐     ▪────┐            
   │        │       │  │  │   │   │       │     │    │            
   │        │       │  │  │   │   │       │     │    │            
 0 └────────▪───────┴──▪──┴───▪───┴───────▪─────┴────▪───────▶  t 
   t₀       t₁      t₂ t₃ t₄  t₅  t₆      t₇    t₈   t₉

This provides us with a nice step-graph. Now, we can most definitely provide an answer for f(t) given any t that has occurred.

Basic Approach

Let’ start thinking about the shape of the algorithm. The simplest approach is to simply loop through the input and return the correct value based on the time range.

Here is a sample program based on the above input graph:

let t₀ = 0,  t₁ = 4,  t₂ = 8,  t₃ = 10, t₄ = 12
let t₅ = 15, t₆ = 18, t₇ = 22, t₈ = 25, t₉ = 28

let up = 1, down = 0

struct Range { let start: Int, end: Int }
struct Input { let range: Range, value: Int }

var inputs: [Input] = []

// Simulate an input stream...
inputs.append(Input(range: Range(start: t₀, end: t₁), value: up))
inputs.append(Input(range: Range(start: t₁, end: t₂), value: down))
inputs.append(Input(range: Range(start: t₂, end: t₃), value: up))
inputs.append(Input(range: Range(start: t₃, end: t₄), value: down))
inputs.append(Input(range: Range(start: t₄, end: t₅), value: up))
inputs.append(Input(range: Range(start: t₅, end: t₆), value: down))
inputs.append(Input(range: Range(start: t₆, end: t₇), value: up))
inputs.append(Input(range: Range(start: t₇, end: t₈), value: down))
inputs.append(Input(range: Range(start: t₈, end: t₉), value: up))
inputs.append(Input(range: Range(start: t₉, end: Int.max), value: down))

func f(t: Int) -> Int {
    for input in inputs {
        if input.range.start <= t && t < input.range.end {
            return input.value
        }
    }
    
    return inputs.last?.value ?? Int.min
}

Then we can simply call the function to get our results:

f(0)     // -> 1
f(29)    // -> 0
f(16)    // -> 0
f(22)    // -> 0

Notice that we can call f(t) in any order and it all works.

Optimization

Now, there is a problem with the above implementation: as the game progresses, more and more input will be generated. This is not good… this is an O(n) algorithm. What we want to as close to is the O(1) algorithm that is available to us in non-FRP world.

Well, one simple approach is to use the previous result as a hint. Here’ the new function f(t).

func f(t: Int, _ index: Int? = nil) -> (value: Int, index: Int) {
    let start = index ?? 0
    let forward = 1, reverse = -1

    let len = inputs.count
    let step = t < inputs.get(start)?.range.start ? reverse : forward

    // search loop
    for var idx = start; 0 <= idx && idx < len; idx += step {
        let input = inputs[idx]
        if input.range.start <= t && t < input.range.end {
            return (input.value, idx)
        }
    }

    let value = (step == forward) ?
        inputs.last?.value ?? Int.min :
        inputs.first?.value ?? Int.min;

    return (value, 0)
}

The major updates are:

  1. Return a tuple (value, index) that can provide us a hint as to the index into the inputs history to start at.
  2. Based on the given index, we can also determine the search order.

Note: I’m using an extension to Array; you can find it here: Array.get.

The updated usage code:

let f₀  = f(0)
let f₁₆ = f(16, f₀.index + 1)
let f₂₂ = f(22, f₁₆.index + 1)
let f₂₉ = f(29, f₂₂.index + 1)

When they are called in the expected time order, the number of times through the “search loop” above is reduced from 25 down to 10. The thing to note from the value 10 here, is that this is the minimum number of searches required for this approach.

That’ great!

Also, imagine if there were thousands of inputs. The value of 25 above would be significantly higher as each search would be starting at index 0. With this new optimized approach, the number searches will be bound by the number of inputs that have happened since the last call of f(t).

It’s good to note that you could still call this version of the function in any order and all should still be good. The the index hint is only used as the starting search point in the inputs array.

Summary

This approach is looking pretty solid to me, though, I’ve only really played around with it in the playground and with fake, simulated input data. Next time, I’ll explore out how this algorithm looks with real input handling code.

Prototyping Practical FRP

Value Add – Bring Something to the Table

There was a comment on my Programming Theory and Practice blog article about a reactive solution for interacting with IOHIDManager. The full gist of it can be found here: https://gist.github.com/mprudhom/607560e767942063baaa.

My thoughts on it can be summed up essentially as:

  1. It requires another library to actually see the code that is going on (the ChannelZ lib from the author), that is bad.
  2. The solution requires bridging from Swift to ObjC back to Swift again, that is bad (though it cannot currently be avoided).
  3. It is no better than the ObjC or C

The last point is the real kicker for me, especially as of late. If I'm going to invest in a new technology, I want to understand the value that I'm getting back from it. In other words: am I getting a good ROI (return on investment) from it?

The thing is, we can write the same "reactive-style" API today, in C or C compiler). To me, this is very valuable and is currently a significant negative (really, a potential deal-breaker for me) against Swift1. We don't know the plans for Swift, so it's hard to say what is going to happen here, and I am personally not interested in any of the managed ports I've been seeing for other platforms.

Thinking About the API

The API for the reactive-style needs to care about three basic things:

  1. connect – we need to know when a new device has been connected
  2. disconnect – we need to know when a device has been disconnected
  3. input – we need to know when the input has changed

When we implement these things, we can do so in a pull, push, or a push-pull manner. My primary use case is for a game, so I'm going to use the pull model. This means that I want my input to actually be a collection of input values since the last time I requested them. I'm also going to ignore connect and disconnect for this example as they are really not that interesting and adds very little to this example.

The API is starting to look like this:

struct DeviceManager {
    var input: [Input]
    let hidManager: IOHIDManagerRef
}

The C

struct DeviceManager {
    std::vector<Input> input;
    IOHIDManagerRef hidManager;
};

Let's also say that Input looks like this:

enum Input {
    case Mouse(x: Int, y: Int, buttons: [ButtonState] /* only want max of 5 */)
    case Keyboard(keyCode: VirtualKey, state: KeyState)
}   

To model that in C

namespace DeviceType {
    enum Type { Mouse, Keyboard };
};

struct Input {
    DeviceType::Type type;

    union {
        struct { /* Mouse */
             int x;
             int y;
             ButtonState buttons[5];
        };
        struct { /* Keyboard */
            VirtualKey keyCode;
            KeyState state;
        };
    };
};

Clearly, the Swift version has some nice wins on syntax here.

Now, I said that I'm using the pull-model, so I have some update function:

func update() { /* The signature doesn't matter... */
    let mouseInputs = filter(manager.inputs) {
        switch ($0) {
             case let .Mouse(_): return true
             default: return false
        }
    }
    // do something interesting with the filtered mouse signals
}

I'm not sure if there is a better way to do that check with associated enum values, but it kinda sucks. The C

void update() {
    auto mouseInputs = filter(manager.inputs, [] (DeviceInput input) {
        return input.type == DeviceType.Mouse;
    });
    // do something interesting with the filtered mouse signals
}

Ironically, the C

What's the Value?

The above example is only a subset of the full solution, but it is not really that far off from being complete. For me, I've been looking at and really wondering what the ROI is going to be for me to fully invest in learning and using Swift. Honestly, I'm not sure.

At this point, it is really starting to look like that I should just go back to C11 features, there is really not a whole lot that Swift can do over C

  1. Lack of code portability
  2. Lack of code interoperability
  3. Lack of full memory control

Yes, it is true that each of these also has a cost associated with it in regards to C

Remember, Swift is still in its infancy – it is going to need to get a lot more sophisticated to realize its aspirations, especially to become a "systems level language".

For me personally, I think it is going to be a much better use of my time writing modern C

Your mileage may vary.

  1. You need to evaluate this for your own needs; this type of cross-platform sharing may be of little to no value for you.
Value Add – Bring Something to the Table

Programming Theory and Practice

Note: This is a bit of a personal reflection exploratory post; if you are looking for deep insights into the Swift language or programming in general, you're probably not going to find much here.

A little Swift aside for some context?

So why did I even start to go down this route of exploration into FRP? Well, I wanted to create an API that felt natural in Swift for interacting with the IOHIDManager class for a prototype of a game idea that I have (thanks to much motivation from Handmade Hero). This is the only way that know how to interact with multiple gamepads, keyboards, and mice to build a proper platform layer for a game on OS X (and potentially iOS).

It turns out, building this in Swift is a pretty bad experience. The IOHIDManager class relies on C callback functions for device connection, removal, and input. This is the point in my Swift work that I know is just going to be painful as I've done it multiple times now. The only way for this to work 1 is to:

  1. Create a C file (and corresponding header) to actually implement the callbacks
  2. Export that callback in a variable so that Swift can use it
  3. Create another Swift class with the @objc attribute so that I can pass data from C back into Swift via this class. Of course, this class needs to be public which artificially adds an implementation detail to the public interface, which I also really dislike.

Ok, this is easy to do, but annoying. Also, at this point, I have now introduced a lot of overhead for dealing with input events, both in terms of code required and runtime costs. I don't like this at all… and I need to do for keyboard, gamepad, and mouse events.

What's really annoying, I just simply wanted to start prototyping with something like this:

public enum VirtualKey {
    case A
    // ...
}

public enum KeyState {
    case Up
    case Down
}

public struct MergedKeyState {
    let key: VirtualKey
    let start: KeyState
    let transitions: Int
}

public struct KeyboardInput {
    var samples: [VirtualKey : [KeyState]]

    public init() {
        self.samples = [VirtualKey : [KeyState]]()
        self.samples[VirtualKey.A] = [KeyState]()
    }

    public mutating func add(key: VirtualKey, state: KeyState) {
        samples[key]?.append(state)
    }

    public mutating func key(key: VirtualKey) -> [KeyState] {
        if let input = self.samples[key] {
            self.samples[key]?.removeAll()
            return input
        }
        else {
            return []
        }
    }

    public mutating func keyA() -> MergedKeyState? {
        let merged: MergedKeyState? = reduce(self.key(.A), nil) {
            merged, state in
            if let merged = merged {
                return MergedKeyState(key: merged.key,
                    start: merged.start,
                    transitions: merged.transitions + 1)
            }
            else {
                return MergedKeyState(key: .A, start: state, transitions: 0)
            }
        }

        return merged
    }
}

Is this a good approach to the problem? I don't know, that's why I'm prototyping out potential solutions. There is a bunch of mutating attributes, that might be bad… but the point is, the only way I could actually start playing with this is to remove it from the context of the problem all together because of the C interop issues.

So what's my point?

Excellent question! Honestly, I don't even know if I'm quite sure. I have a lot of thoughts in my head around many tangentially related topics, but I guess if we focus it merely on this trend in functional programming and FRP implementations, I feel like I have to be missing something because all I really see is this: a very primitive architecture for a game engine.

If you are using "pull" to get the data, you really are simply handling input just like many game engines would. That input cascades changes down some structure of data to determine what needs to be updated and re-drawn.

If you are using a "push" model, you've really just implemented a potentially nicer way doing exactly what you are doing today with event driven or notification driven UI patterns. Yes, there are some nice things we can do here, but this seems to continue with one of the biggest problems: mutations from random places at random times, albeit, maybe slightly more controlled.

I guess at the end of it all I have a bit of melancholy about the whole situation. I wish more people were thinking up these models and really applying them to the hardware instead of using the hardware to, essentially, brute force the conceptual model into working on our current hardware.

  1. As of Xcode 6.3 beta 2…
Programming Theory and Practice

Handling Multiple Closure Parameters

So Natasha has a fair criticism about auto-completion1 in Xcode with regards to functions that take multiple closures and Swift's trailing closure syntax. I think there are many issues with auto-complete and Swift, but that's different rabbit hole to go down.

Instead, what I wanted to focus on was another way to solve the problem, which also helps with the auto-complete issue.

Here's the basic original problem:

func doSomething(value: Int, onSuccess: () -> (), onError: () -> ()) {
    if value == 0 {
        onSuccess()
    }
    else {
        onError()
    }
}

So instead of writing code in one the following ways (which all have the weird multiple closure issue):

doSomething(5, { println("success") }, { println("error") })
doSomething(0, { println("success") }) { println("error") }
doSomething(5, { println("success") }, { println("error") })

We can restructure the code using a very simple promise model.

struct CallbackResult<T> {
    let value: T
    let failed: Bool

    func onError(fn: (value: T) -> ()) -> CallbackResult<T> {
        if self.failed {
            fn(value: value)
        }

        return self
    }

    func onSuccess(fn: (value: T) -> ()) -> CallbackResult<T> {
        if !self.failed {
            fn(value: value)
        }

        return self
    }
}

func doSomething(value: Int) -> CallbackResult<Int> {
    return CallbackResult(value: value, failed: value != 0)
}

Then the usage becomes:

doSomething(10)
    .onSuccess { println("foo(\($0)): success") }
    .onError { println("foo(\($0)): error") }

doSomething(0)
    .onSuccess { println("foo(\($0)): success") }
    .onError { println("foo(\($0)): error") }

If you are familiar with JavaScript, you'll see a similar thing with deferred objects in jQuery and lots of other places as well.

There are lots of other benefits to this approach as well, such as helping flatten out async code that has a bunch of callbacks in it.

Anyhow, just another option.

  1. So I just realized that this was an old post of hers… auto-complete is still as terrible as ever though. Maybe one day.
Handling Multiple Closure Parameters

Swift Namespaces

I've seen some people complaining about the lack of namespaces in Swift… well, I'm not sure if I've seen this anywhere else, but you can fake namespaces if you really must.

enum std {
    static func add(x: Int, _ y: Int) -> Int { return x + y }

    enum more {
        static func sub(x: Int, _ y: Int) -> Int { return x - y }
    }

    struct apples {
        var count: Int;
    }
}

std.add(1, 2)
std.more.sub(1, 2)

var apples = std.apples(count: 12)
apples.count = 10

Now, I don't really recommend this, but it's kind of fun to hack around sometimes.

Update

Oh… and we can mimic using too:

typealias m = std.more
m.sub(1, 2)

I think you still need to have it qualified though, so no naked use of sub.

Swift Namespaces

Swift’s Protocol Extension

I have been working on porting over my ObjC platform layer from

Handmade Hero and I have a bit of code that looks like this:

self.aboutMenuItem.title = [self.aboutMenuItem.title
                            stringByReplacingOccurrencesOfString:DEADZONE_TITLE
                            withString:APP_NAME];
self.hideMenuItem.title = [self.hideMenuItem.title
                           stringByReplacingOccurrencesOfString:DEADZONE_TITLE
                           withString:APP_NAME];
self.quitMenuItem.title = [self.quitMenuItem.title
                           stringByReplacingOccurrencesOfString:DEADZONE_TITLE
                           withString:APP_NAME];
self.helpMenuItem.title = [self.helpMenuItem.title
                           stringByReplacingOccurrencesOfString:DEADZONE_TITLE
                           withString:APP_NAME];
self.window.title = [self.window.title
                     stringByReplacingOccurrencesOfString:DEADZONE_TITLE
                     withString:APP_NAME];

The point of this code is to go through and replace all of the text with the

target name in it to a string defined by a config file. But you can easily

imagine that this is any code that is starting to look fairly redundant across

a set of various differently typed items.

This is really just a simple case of iterating over the items in the collection and calling the title setting.

for (var item) in items {
    item.title = item.title.replace(placeholder, withString: title)
}

The astute readers out there may have caught an issue with this approach though. For one, a window is of type NSWindow and the other items are of type

NSMenuItem. That's not going to work as they share no base class that contains a title property.

We have two choices here:

  1. Handle window on it's own separate line, or 2. Create a protocol extension so they do have a common interface with a title

property.

I want my code to capture the intent as much as possible with as little redundancies as possible, so option #1 is out.

So, let's think about option #2. What I really want to say is that both

NSWindow and NSMenuItem share a common set of behaviors, or more specifically in this case, a single behavior: title.

Now, it seems that they actually already do share this behavior and that it is just not codified. However, if you look at the declaration of each, you'll notice that NSWindow actually returns a String? for title and NSMenuItem returns a String (note the optional vs. non-optional difference).

Ok… that's annoying, but we can work around that!

protocol HasTitle {
    var ht_title: String { get set }
}

extension NSMenuItem: HasTitle {
    var ht_title: String {
        get { return self.title }
        set { self.title = newValue }
    }
}

extension NSWindow : HasTitle {
    var ht_title: String {
        get { return self.title ?? "" }
        set { self.title = newValue }
    }
}

With the protocol extension HasTitle, we have now codified what the behavior semantics are. It's then trivial to implement that appropriately for each type that you want to share this HasTitle codification.

The final code to make use of this now looks like:

let items: [HasTitle] = [aboutItem, hideItem, quitItem, helpItem, window]
for (var item) in items {
    item.ht_title = item.ht_title.replace(placeholder, withString: title)
}

I almost forgot… you'll probably paste this code in and wonder why it is not

working for you. I've created an extension on String that adds the replace

function. It simply forwards the parameters into

stringByReplacingOccurrencesOfString.

Now, unfortunately, Swift needed a little bit of type annotation help to make it all work 100%, but we've done it. With one simple protocol and two easy class extensions, our usage code has become significantly cleaner, easier to update, and less error prone.

Could we bring this technique back to ObjC? Of course. Just write the simple for-loop to begin with. However, you'll probably stop there because that is all that is needed to make the ObjC side happy as we can send messages to any object instance; we can completely forgo the HasTitle protocol.

However, that is the part that I think it vastly more important as it's that protocol that leads us into thinking about better composition models. I hope to do a longer blog post about that at another time.

Happy Swifting!

Update, February 16th: I removed the usage1 of map as it was an abuse of the function. I used it because I didn't want to use the ugly version of the for-loop and I was having issues with the iterative version. Turns out I just need (var item) instead of var item. Seems like a compiler bug to me…

  1. Ok… it was really a very bad abuse of the map() function.
Swift’s Protocol Extension

Swift v1.2 β2 Performance

I've been taking a look at performance of Swift for a while now, with two very specific focus points:

  1. Developer workflow (non-optimized builds)
  2. Real-time applications (fully-optimized builds)

I'm very happy to report that Swift v1.2 β2 seems to have made some really great improvements in performance, even over Swift v1.2 β1.

Performance Numbers1

Language: C, Optimization: -O0                    ┃  6.3 β2  ┃  6.3 β1  ┃  6.1.1   ┃
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━┩
RenderGradient (Pointer Math)                     │   38.651 │   38.266 │   38.780 │
──────────────────────────────────────────────────┴──────────┴──────────┴──────────┘

Language: C, Optimization: -Os                    ┃  6.3 β2  ┃  6.3 β1  ┃  6.1.1   ┃
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━┩
RenderGradient (Pointer Math)                     │   10.374 │   10.042 │   10.162 │
──────────────────────────────────────────────────┴──────────┴──────────┴──────────┘

Language: C, Optimization: -Ofast                 ┃  6.3 β2  ┃  6.3 β1  ┃  6.1.1   ┃
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━┩
RenderGradient (Pointer Math)                     │    3.112 │    3.022 │    2.976 │
──────────────────────────────────────────────────┴──────────┴──────────┴──────────┘

Language: Swift, Optimization: -Onone             ┃  6.3 β2  ┃  6.3 β1  ┃  6.1.1   ┃
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━┩
RenderGradient ([Pixel])                          │ 3684.914 │ 4012.283 │ 29134.32 │
RenderGradient (UnsafeMutablePointer)             │ 171.3359 │ 162.9272 │ 152.2643 │
RenderGradient ([Pixel].withUnsafeMutablePointer) │ 386.9801 │ 523.7199 │ 1159.273 │
──────────────────────────────────────────────────┴──────────┴──────────┴──────────┘

Language: Swift, Optimization: -O                 ┃  6.3 β2  ┃  6.3 β1  ┃  6.1.1   ┃
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━┩
RenderGradient ([Pixel])                          │ 26.91437 │ 46.57198 │ 66.40995 │
RenderGradient (UnsafeMutablePointer)             │ 22.71384 │ 21.74668 │ 22.21477 │
RenderGradient ([Pixel].withUnsafeMutablePointer) │ 22.33094 │ 39.78517 │ 39.62590 │
──────────────────────────────────────────────────┴──────────┴──────────┴──────────┘

Language: Swift, Optimization: -Ounchecked        ┃  6.3 β2  ┃  6.3 β1  ┃  6.1.1   ┃
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━┩
RenderGradient ([Pixel])                          │ 19.66853 │ 40.28331 │ 66.04476 │
RenderGradient (UnsafeMutablePointer)             │ 20.02236 │ 19.53774 │ 19.51404 │
RenderGradient ([Pixel].withUnsafeMutablePointer) │ 20.25013 │ 41.26989 │ 38.34509 │
──────────────────────────────────────────────────┴──────────┴──────────┴──────────┘

This is great! The worst case, [Pixel], in non-optimized builds was 29s back in Xcode 6.1.1 (the latest official build). In latest beta, that's down to 3.6s! Sure, that's still a horribly slow time, but that's still a massive improvement.

The other thing to note is that nearly all of the optimized builds got twice as fast as before. The biggest thing to note here is that the usage of arrays is now just as good in optimized builds as the pointer versions. That's a big win for code clarity. Once the debug performance of arrays is fully addressed, this will be even better.

Hopefully 6.3 β3 shows just as remarkable improvements.

Also, I've started a GitHub repo to start tracking this stuff better:

https://github.com/owensd/swift-perf.

Feel free to send any pull requests for items you'd like to see tracked here. I do plan on doing some updates to the infrastructure piece of it to get some easier delta reporting.

  1. The times should be read as: "the amount of time, in milliseconds, it took to compute 30 iterations".
Swift v1.2 β2 Performance

Swift v1.2 Performance

In a series of posts I wrote a few weeks back, I looked at the performance of Swift in the context of debug (e.g. non-optimized) builds. The developer workflow pain that I was having was significant.

Of course, today a new build of Xcode dropped that finally (I jest a little) contained a new build of Swift: Swift v.1.2.

So, is it any better?

I've spent about ten minutes playing around with my projects (described in the blog posts mentioned above). I ran into the following issues:

  • Xcode crashed opening a source file (/sigh)
  • Swift v1.2 conversion missed updating two cases:
  • Byte was removed and not automatically changed to UInt8 in the

    initializer case.

  • UnsafeMutablePointer<Pixel>.null() was not replaced to it's proper usage:

    let pixels: UnsafeMutablePointer<Pixel> = nil.

The crash was annoying. However, the Swift conversion process went well and I don't really care that they missed those two cases.

So…?

SO MUCH BETTER!! BUT…

The ObjC optimized RenderWeirdGradient() function looked like this:

void RenderGradient(RenderBufferRef buffer, int offsetX, int offsetY)
{
    int width = buffer->width + offsetX;
    int height = buffer->height + offsetY;
    uint32_t *pixel = (uint32_t *)&buffer->pixels[0];

    for (int y = offsetY; y < height; ++y) {
        for (int x = offsetX; x < width; ++x) {
            *pixel = 0xFF << 24 | (x & 0xFF) << 16 | (y & 0xFF) << 8;
            ++pixel;
        }
    }
}

The timings I saw on my machine here:

-O0   0.038723s
-Os   0.010972s

I tested against three different Swift loops:

Raw UnsafeMutablePointer

func RenderGradient(var buffer: RenderBuffer, offsetX: Int, offsetY: Int)
{
    var offset = 0
    for (var y = 0, height = buffer.height; y < height; ++y) {
        for (var x = 0, width = buffer.width; x < width; ++x) {
            let pixel = Pixel(
                red: 0,
                green: UInt8((y + offsetY) & 0xFF),
                blue: UInt8((x + offsetX) & 0xFF),
                alpha: 0xFF)
            buffer.pixels[offset] = pixel;
            ++offset;
        }
    }
}

Pixel Array

func RenderGradient(inout buffer: RenderBuffer, offsetX: Int, offsetY: Int)
{
    // I truly hope you have turned down the number of iterations or you have picked
    // up a new build of Swift where this is not dog slow with -Onone.
    var offset = 0
    for (var y = 0, height = buffer.height; y < height; ++y) {
        for (var x = 0, width = buffer.width; x < width; ++x) {
            let pixel = Pixel(
                red: 0,
                green: UInt8((y + offsetY) & 0xFF),
                blue: UInt8((x + offsetX) & 0xFF),
                alpha: 0xFF)
            buffer.pixels[offset] = pixel;
            ++offset;
        }
    }
}

Pixel Array with UnsafeMutablePointer

func RenderGradient(inout buffer: RenderBuffer, offsetX: Int, offsetY: Int)
{
    buffer.pixels.withUnsafeMutableBufferPointer { (inout p: UnsafeMutableBufferPointer<Pixel>) -> () in
        var offset = 0
        for (var y = 0, height = buffer.height; y < height; ++y) {
            for (var x = 0, width = buffer.width; x < width; ++x) {
                let pixel = Pixel(
                    red: 0,
                    green: UInt8((y + offsetY) & 0xFF),
                    blue: UInt8((x + offsetX) & 0xFF),
                    alpha: 0xFF)
                p[offset] = pixel
                ++offset;
            }
        }
    }
}

With -Onone, the timings are (the diff % is compared against the optimized ObjC code presented above):

Swift v1
Swift Rendering Tests: 30 iterations per test
---------------------
UnsafeMutablePointer<Pixel>     avg time: 0.186799s
[Pixel]                         avg time: 27.9754s
[Pixel].unsafeMutablePointer()  avg time: 1.18535s
Swift v1.2
Swift Rendering Tests: 30 iterations per test
---------------------
UnsafeMutablePointer<Pixel>     avg time: 0.185078s, stddev: 0.00442746s, diff: -377%
[Pixel]                         avg time: 3.92371s, stddev: 0.0777589s, diff: -10032%
[Pixel].unsafeMutablePointer()  avg time: 0.518955s, stddev: 0.00921328s, diff: -1239%

With -O, the timings are:

Swift v1
Swift Rendering Tests: 30 iterations per test
---------------------
UnsafeMutablePointer<Pixel>     avg time: 0.0223397s
[Pixel]                         avg time: 0.0287606s
[Pixel].unsafeMutablePointer()  avg time: 0.0402743s
Swift v1.2
Swift Rendering Tests: 30 iterations per test
---------------------
UnsafeMutablePointer<Pixel>     avg time: 0.022574s, stddev: 0.00115951s, diff: -105%
[Pixel]                         avg time: 0.0268918s, stddev: 0.00143757s, diff: -144%
[Pixel].unsafeMutablePointer()  avg time: 0.0414112s, stddev: 0.00207772s, diff: -276%

There are few large takeaways here:

  1. The raw UnsafeMutablePointer<Pixel> is still significantly faster, in all

scenarios; no performance change between Swift versions. 2. The [Pixel] has significantly better performance than before. It seems

the optimized build even got slightly faster. HOWEVER, the array solution

is still not good enough as it can only render at about 7 to 8Hz (target is

30Hz). 3. Keeping the [Pixel] array and using the unsafeMutablePointer() call for

"hot areas" of your code has also gotten much better. It now gets us to the

target 30Hz in non-optimized builds, but still nearly 3x slower than

simply using an UnsafeMutablePointer<Pixel> to begin with.

My key takeaway:

Swift is getting better and faster but it's still not suitable in the domain

space I'm currently working in for this project: high-performance, real-time

systems.

Eagerly awaiting Swift vNext!

Swift v1.2 Performance

Swift, Protocols, and Composition

Ash Furrow wrote up this post yesterday: http://ashfurrow.com/blog/protocols-and-swift/. It's a good post, you should read it. The problem he outlines is this:

"Here's the problem: you have two types that want to talk to each other."

Ash's solution to the problem was to use protocols to essentially turn the problem inside out. His solution definitely works and it's better than his original way of doing it. It did get me thinking about solving the same problem in maybe a slightly more flexible way.

The drawback with Ash's solution, in my opinion, is that it still takes a heavy leaning on an object-oriented paradigm. I don't think we need that, especially in this case.

If we break down the problem into parts, I think we end up with this:

  1. A set of nutritional information (calories and hydration level). 2. Types of food (wet and dry) that can affect that nutritional information. 3. An animal type (cat) that has a set of nutritional information and the

ability to eat food.

The issue with the object-oriented approach is that it coupled the notion of eating with the animal type (see the eat extension). I don't think we really want that. Instead, we want to capture the relationship between food and nutrition through some eat function.

Let's setup the types:

enum Food {
    case Dry(caloriesPerGram: Double)
    case Wet(caloriesPerGram: Double, hydrationPerGram: Double)
}

protocol Nutrition {
    var calorieCount: Double { get set }
    var hydrationLevel: Double { get set }
}

struct Cat: Nutrition {
    var calorieCount: Double = 0
    var hydrationLevel: Double = 0
}

Ok, so what do we have:

  • The Food type is an enum because we have clear restrictions on the type of

food available and how it impacts Nutrition.

  • The Nutrition item is a protocol that defines the data that it needs. This

is done because we are saying that a cat "has a" set of nutrition information.

  • The Cat is simply a data type that is made up of Nutrition data.

The last thing we are missing is the ability to eat. If you are thinking about objects then I think the obvious thing to do is to add an eat function on

Nutrition. There is another approach though: thinking instead about the transformations of the data.

Because I care more about transforming data, I'm going to create a top-level function eat:

func eat(var nutrition: Nutrition, food: Food, grams: Double) -> Nutrition {
    switch food {
    case let .Dry(caloriesPerGram):
        nutrition.calorieCount += caloriesPerGram * grams
    case let .Wet(caloriesPerGram, hydrationPerGram):
        nutrition.calorieCount += caloriesPerGram * grams
        nutrition.hydrationLevel += hydrationPerGram * grams
    }

    return nutrition
}

func eat<T: Nutrition>(nutrition: T, food: Food, grams: Double) -> T {
    return eat(nutrition, food, grams) as T
}

There are a few things to note:

  1. The var usage in the parameter list just let's us get a copy of that

parameter and use it locally as a new variable. 2. There is absolutely no coupling with any of the types that could possibly

contain Nutrition information. 3. There is a generic version so we do not have to cast when dealing with

concrete implementations of Nutrition, such as Cat.

The usage of the code looks like this:

let kibble = Food.Dry(caloriesPerGram: 40)
let fancyFeast = Food.Wet(caloriesPerGram: 80, hydrationPerGram: 0.2)

var dave = Cat()
dave = eat(dave, kibble, 30)
dave = eat(dave, fancyFeast, 20)

And then we can do some other more functional oriented operations a bit more naturally:

let cats = [Cat(), Cat(), Cat(), Cat(), Cat(), Cat(), Cat()]
let caloriesEatenByCats = reduce(map(cats) { cat in
    eat(cat, kibble, 30) }, 0) { sum, cat in
        sum + cat.calorieCount }

But here is where the really nice part of this choice comes along: if I want to add a Dog type, I only need to create the struct for it I'm done.

struct Dog: Nutrition {
    var calorieCount: Double = 0
    var hydrationLevel: Double = 0
}

let dogs = [Dog(), Dog(), Dog(), Dog()]
let caloriesEatenByDogs = reduce(map(dogs) { dog in
    eat(dog, kibble, 30) }, 0) { sum, dog in
        sum + dog.calorieCount }

In Ash's implementation, you have to then go add an eat function on each new type you are dealing with. We lose no flexility either because if a Dog is supposed to eat differently, we can just create an overload for it.

The other nice part is we can mix and match our Nutrition types like this:

let animals: [Nutrition] = [Dog(), Cat()]
let caloriesEatenByAnimals = reduce(map(animals) { animal in
    eat(animal, kibble, 30) }, 0) { sum, animal in
        sum + animal.calorieCount }

It's just another way of thinking about the problem. Swift seems to be a language that values immutability and composition over mutability and if we start to think about solving problems that way, I think we end up with more solutions like I presented where it's really just about how we manipulate the data in composable ways.

Source: https://gist.github.com/owensd/7bda3f7b3f91245e3542

Swift, Protocols, and Composition