October 27, 2014

Links for October 27, 2014

CMDeviceMotion

My first article — about CMDeviceMotion and the Core Motion framework — is up at NSHipster:

Beneath the smooth glass of each shiny iPhone, nestled on a logic board between touch screen controllers and Apple-designed SoCs, the gyroscope and accelerometer sit largely neglected.

by Nate Cook swift cmdevicemotion nshipster


October 8, 2014

Loopy, Random Ideas for Extending "enum"

Enumerations are a great, Swift-specific language feature. Due to their extensibility, what is a simple list of options in another language can have extremely useful additional features. Let’s take a look at how we can add a few to the default enum type: a nice description, a list of all possible values, and a method to choose a random case.

Covering our bases

To add these additional features, we first need to give our enum an integer base type. Swift enumerations don’t actually require any base type - the compiler handles all that for you if you leave it out, but basing ours on Int will set us up well.1 Let’s have an enumeration of Santa’s reindeer:

enum Reindeer: Int {
    case Dasher, Dancer, Prancer, Vixen, Comet, Cupid, Donner, Blitzen
    // and don't forget Rudolph!
    case Rudolph   
}

println(Reindeer.Rudolph)
> > (Enum Value)

Well, that’s not exactly what we wanted. It would be nice to be able to print these names out, but since we’re already using Int for the base type of Reindeer, we can’t set the raw values to be string versions of the case names. Instead, let’s conform to the Printable protocol2 this way:

extension Reindeer: Printable {
    var description: String { 
        let names = ["Dasher", "Dancer", "Prancer", "Vixen", "Comet", "Cupid", "Donner", "Blitzen", "Rudolph"]
        return names[self.rawValue] 
    }
}

println(Reindeer.Rudolph)
> > Rudolph

Enumerating our enumeration

It would be great if we could list all of Santa’s reindeer, but Swift enumerations don’t support looping over their cases. With another data type, we might extend to conform to SequenceType or CollectionType, but with an enumeration that doesn’t make sense – any instance of Reindeer is a single value of the group; we wouldn’t want to loop over .Prancer. Instead, let’s add a static allCases computed property that returns an array of all the cases. First the code, then an explanation:

extension Reindeer {
    static var allCases: [Reindeer] {
        var cur = 0
        return Array(
            GeneratorOf<Reindeer> {
                return Reindeer(rawValue: cur++)
            }
        )
    }
}

for reindeer in Reindeer.allCases {
    println("On \(reindeer.description)!")
}
> > On Dasher!
> > On Dancer!
> > On Prancer!
> > you get the idea

So what’s going on there? This returns an Array, using the initializer that takes any SequenceType. That role is filled by a GeneratorOf that returns each reindeer, starting with a raw value of zero and incrementing until Reindeer(rawValue: cur) returns nil. Of course, if this seems like overkill, you can manually provide an array of all the cases instead:

extension Reindeer {
    static let allCases: [Reindeer] = [.Dasher, .Dancer, .Prancer, .Vixen, .Comet, .Cupid, .Donner, .Blitzen, .Rudolph]
}

Pick a reindeer, any reindeer

Lastly, since it’s only fair that each reindeer gets a turn, it would be nice to be able to select a random reindeer to lead the pack (except for on foggy Christmas Eves). Here’s how we could do that, first by calculating the number of cases in our enumeration, then generating a random raw value less than the maximum:

extension Reindeer {
    static var caseCount: Int {
        var max: Int = 0
        while let _ = self(rawValue: ++max) {}
        return max
    }
    
    static func randomCase() -> Reindeer {
        // everybody do the Int/UInt32 shuffle!
        let randomValue = Int(arc4random_uniform(UInt32(caseCount)))
        return self(rawValue: randomValue)!
    }
}

let randomReindeer = Reindeer.randomCase()
switch randomReindeer {
case .Rudolph:
    println("Shiny nose")
default:
    println("Matte-finish nose")
}

Please note: all these examples use the Swift 1.1 syntax for initializing from a raw value. For code compiled with Xcode 6.0, you’ll need to use the older syntax:

// Xcode 6.0
let myReindeer: Reindeer? = Reindeer.fromRawValue(3)

// Xcode 6.1
let myReindeer: Reindeer? = Reindeer(rawValue: 3)
  1. Note that all these features will only work enumerations that can have sequential, integer-backed cases - if you’re doing something with associated values or need specific raw values, the implementation would be different.

  2. Any day now, playgrounds will start using the description property in println(), and then we’ll be glad we did all this hard work.

by Nate Cook swift enum Comments


September 17, 2014

Slicing for Speed

Understanding the Slice type in Swift

This post has been updated for Swift 1.2.

When I first heard about Swift, I regarded its type inference capabilities as a convenience: type safety without all the typing. What I’ve come to realize, though, is that Swift’s type inference lets it hide a great deal of the subtle ways it makes things faster – things largely “just work,” even if we aren’t always using the types we think we are. Without an understanding of these subtle tricks, however, a programmer might undo the very things that make Swift so… swift.

For example, take the humble Array. We can create a new array, grab a chunk of it, check the length of the chunk, and loop through its contents, like this:

let jennysNumber = [8, 6, 7, 5, 3, 0, 9]    // ee-ai-een
let jennysExchange = jennysNumber[0..<3]
println(jennysExchange.count)
> 3
for digit in jennysExchange {
    println(digit)
}
> 8
> 6
> 7

Let’s check our types, too. Option-click on jennysNumber – yep, it’s an [Int], just like we expected. Do the same with jennysExchange and it’s – ArraySlice<Int>? Where did that come from?

The answer has to do with how Swift can make array operations run at C-like speeds while maintaining type safety and immutability. Read on to learn about slices, and what you need to know to work with them.

What is a slice? Why is it used?

You can think of an ArraySlice as a window into a portion of an existing Array instance. When we subscripted a range of jennysNumber, instead of allocating space in memory for a new array and copying the relevant elements over, Swift essentialy gave us a view of those three elements still inside the jennysNumber array.

let jennysNumber = [8, 6, 7, 5, 3, 0, 9]let jennysExchange = jennysNumber[0..<3]

Early on in the Swift beta, this behavior was completely transparent – the immutability of array elements wasn’t enforced, so you could modify the original array by changing values in a slice. Fortunately, the language was subsequently revised to ensure immutability.

Now, Swift knows whether our new slice is mutable or constant, and it knows when we’re calling any potentially mutating operations on either the slice or the original array. That means it can delay (or completely avoid) duplicating the doubly-referenced data, saving time and memory. The ArraySlice type has its own implementations of all the same methods and properties as Array, so from our perspective using the slice, we don’t really notice that it’s a different type; this optimization is handled transparently for us.

Transparently, that is, until we try to call a method that expects an Array instance:

func concatenateNumbers(numbers: [Int]) -> String {
    let result = numbers.reduce("") { $0 + "\($1)" }
    return result
}

println(concatenateNumbers(jennysNumber))
> "8675309"
println(concatenateNumbers(jennysExchange))
> error: 'ArraySlice<Int>' is not convertible to '[Int]'

Slicing and dicing

How can we work around this? We have three options: we can convert our slice back to an array, we can overload our function with a version that takes a slice, or we can rewrite the function as a generic. Let’s take a look at each option in turn.

.1: Converting back to an Array

Can’t we just cast the slice back to an array?

let jennysExchangeArray = Array(jennysExchange)
println(concatenateNumbers(jennysExchangeArray))
> "867"

Wait! That’s not a cast, that’s the initialization of a brand new array. Instead of getting a window, we’ve created an array and copied over the subscripted contents:

let jennysNumber = [8, 6, 7, 5, 3, 0, 9]let jennysExchange = jennysNumber[0..<3]let exchangeCopy = Array(jennysExchange)

It works, but it defeats the hard work of the good people behind Swift – converting a slice back to an array creates a new backing store filled with the subscripted data. Let’s try something else.

.2: Getting ArraySlice-specific

Here’s an overloaded function that takes a ArraySlice<Int> instead of an [Int]:

func concatenateNumbers(numbers: ArraySlice<Int>) -> String {
    let result = numbers.reduce("") { $0 + "\($1)" }
    return result
}

println(concatenateNumbers(jennysExchange))
> "867"

Okay, now we can let our slice stay a slice, and call concatenateNumbers properly. The only problem is that we’re repeating ourselves – having two versions of the same function is never a good idea. What was option 3?

.3: Generics are a cut above the rest

If we convert concatenateNumbers to a proper generic function, we’ll be able to call it with either the array or the slice. So how do we do that?

In our generic function, we won’t be able to use the reduce instance method, since it’s declared separately in Array and ArraySlice. There is, however, a global reduce function that accepts a parameter conforming to SequenceType. If we check the (sprawling) protocol hierarchy graph on SwiftDoc.org, we can confirm that ArraySlice and Array both conform, so that will be a suitable generic constraint. Here’s our new function:

func concatenateNumbers<S: SequenceType>(numbers: S) -> String {
    let result = reduce(numbers, "") { $0 + "\($1)" }
    return result
}

println(concatenateNumbers(jennysNumber))
> "8675309"
println(concatenateNumbers(jennysExchange))
> "867"

Perfect! No need to reallocate, no need to repeat ourselves.

Performance

If you’re doing a lot of range-based subscripting of arrays, all that allocation can really add up. I ran a test summing random subranges of an array of integers, and found that using a generic function was more than six times faster than converting the subrange to an array each time. Not too shabby!

by Nate Cook swift arrays slices generics Comments


September 5, 2014

Introducing Swifter

So much of Swift is defined internally to the language that it really is fascinating to scan through the built-in type and protocol definitions. I’d found myself wishing for a way to easily browse through these, especially since my version of Xcode refuses to honor my furious command-clicking short of invoking an esoteric process. Some PHP and a few byzantine regular expressions later, I’m happy to take the wraps off Swifter – browsable, auto-generated documentation straight from the import Swift header file.

Swifter
Command-click no more.

Please take a look! You can let me know if I’ve missed anything over on Twitter.

by Nate Cook swift swifter Comments


August 29, 2014

Generic Functions for Incompatible Types

On Stack Overflow, user Carpsen90 asked a question about what protocol to use in a generic function such that it could take any number – Int, Float, Double, etc – without having to revert to NSNumber. This has bitten me a few times, since the integer types (Int, UInt, and their kin) conform to the IntegerType protocol, while Float and Double conform to FloatingPointType, so there’s no shared protocol between them. It’s a little crazy that this isn’t possible right out of the box in Swift, but it does make for a good example of how implementing your own protocols can open up new ways of using generics.

For this post, we’ll implement a minusOneSquared function that gets a number n and returns (n - 1)^2. Our first attempt, without any generic constraints, doesn’t compile:

func minusOneSquared<T>(number: T) -> T {
    let minusOne = number - 1
    > error: cannot invoke '-' with an argument list of type '(T, IntegerLiteralConvertible)'
    return minusOne * minusOne
    > error: cannot invoke '*' with an argument list of type '(T, T)'
}

To write a generic function like this, we’ll first need to create a new protocol declared with whatever methods and operators we’re going to use in the function. The exact details of what the protocol declares will depend on what the generic function needs to do. Our new protocol, NumericType, has the arithmetic operators (so we can multiply and subtract) and an initializer that takes an Int (so we can create a one to subtract from n).

protocol NumericType {
    func +(lhs: Self, rhs: Self) -> Self
    func -(lhs: Self, rhs: Self) -> Self
    func *(lhs: Self, rhs: Self) -> Self
    func /(lhs: Self, rhs: Self) -> Self
    func %(lhs: Self, rhs: Self) -> Self
    init(_ v: Int)
}

All of the numeric types already implement these, but at this point the compiler doesn’t know that they conform to the new NumericType protocol. We have to make this explicit by using an empty extension – Apple calls this “declaring protocol adoption with an extension.” We’ll do this for Double, Float, and all ten integer types:

extension Double : NumericType {}
extension Float  : NumericType {}
extension Int    : NumericType {}
extension Int8   : NumericType {}
extension Int16  : NumericType {}
extension Int32  : NumericType {}
extension Int64  : NumericType {}
extension UInt   : NumericType {}
extension UInt8  : NumericType {}
extension UInt16 : NumericType {}
extension UInt32 : NumericType {}
extension UInt64 : NumericType {}

Finally, we can write a working function, using the NumericType protocol as a generic constraint, and call it with any numeric type we like.

func minusOneSquared<T : NumericType>(number: T) -> T {
    // uses init(_ v: Int) and the - operator
    let minusOne = number - T(1)
    
    // uses * operator
    return minusOne * minusOne
}

minusOneSquared(5)              // 16
minusOneSquared(2.3)            // 1.69
minusOneSquared(2 as UInt64)    // 1

by Nate Cook swift generics protocols extensions Comments