Be aware of your enumerated types

Posted Oct 18, 2015

When you are working with Apples Foundation framework you have probably stumbled across NS_ENUM and NS_OPTIONS (since iOS 6 and OS X Mountain Lion). Both NS_ENUM and NS_OPTIONS are marcros that use the C enum under the hood, and if you have used C enums before you will probably understand these macros, kind of, right away.

So why do we need these macros? NS_ENUM and NS_OPTIONS makes it easy for developers to specify the underlying type and size of your enumeration. This is handy since we, developers for Apple plattforms, may need to compile our applications to run on both 32-bit and 64-bits processor architectures. So by defining the type of the enumeration to be NSInteger or NSUInteger, the compiler can decide what the most appropriate size depending processor architecture.

In this post I am going to take a little deeper look at NS_OPTIONS and give a solution to a misstake I often see in the community when using the macro.

NS_OPTIONS

If you are used to C enum, you may also be aware of that enum can be used as bitmasks. This is exactly the use case of NS_OPTIONS. The macro tells the compiler that the values can be combined with bitmask operators, | for bitwise or and & for bitwise and.

Here is an example from UIView.h in UIKit. This is the definition of UIViewAnimationOptions.

typedef NS_OPTIONS(NSUInteger, UIViewAnimationOptions) {
    UIViewAnimationOptionLayoutSubviews            = 1 <<  0,
    UIViewAnimationOptionAllowUserInteraction      = 1 <<  1,
    UIViewAnimationOptionBeginFromCurrentState     = 1 <<  2,
    UIViewAnimationOptionRepeat                    = 1 <<  3,
    UIViewAnimationOptionAutoreverse               = 1 <<  4,
    UIViewAnimationOptionOverrideInheritedDuration = 1 <<  5,
    UIViewAnimationOptionOverrideInheritedCurve    = 1 <<  6,
    UIViewAnimationOptionAllowAnimatedContent      = 1 <<  7,
    UIViewAnimationOptionShowHideTransitionViews   = 1 <<  8,
    UIViewAnimationOptionOverrideInheritedOptions  = 1 <<  9,
    
    UIViewAnimationOptionCurveEaseInOut            = 0 << 16,
    UIViewAnimationOptionCurveEaseIn               = 1 << 16,
    UIViewAnimationOptionCurveEaseOut              = 2 << 16,
    UIViewAnimationOptionCurveLinear               = 3 << 16,
    
    UIViewAnimationOptionTransitionNone            = 0 << 20,
    UIViewAnimationOptionTransitionFlipFromLeft    = 1 << 20,
    UIViewAnimationOptionTransitionFlipFromRight   = 2 << 20,
    UIViewAnimationOptionTransitionCurlUp          = 3 << 20,
    UIViewAnimationOptionTransitionCurlDown        = 4 << 20,
    UIViewAnimationOptionTransitionCrossDissolve   = 5 << 20,
    UIViewAnimationOptionTransitionFlipFromTop     = 6 << 20,
    UIViewAnimationOptionTransitionFlipFromBottom  = 7 << 20,
} NS_ENUM_AVAILABLE_IOS(4_0);

In this definition the shift operator is used to define the values of the constants in the enumeration. For example 1 « 4. What this does is that it takes the bits for decimal 1, and scoot them to the left by four steps. 0 0 0 0 1 will then become 1 0 0 0 0. The value for UIViewAnimationOptionAutoreverse will therefore resolve to decimal 16.

By this definition, all options from UIViewAnimationOptionLayoutSubviews to UIViewAnimationOptionOverrideInheritedOptions can be combined together in any combination. Since these options are using decimal 1 with different shifting. Options can combined by using bitwise or |.

UIViewAnimationOptions options = UIViewAnimationOptionRepeat | UIViewAnimationOptionAutoreverse;
// options = 1 0 0 0 | 1 0 0 0 0 = 1 1 0 0 0 = 24

We can also check if an option is set in the bitmask by using the bitwise and &.

UIViewAnimationOptions options = UIViewAnimationOptionRepeat | UIViewAnimationOptionAutoreverse;
BOOL const shouldRepeat = (options & UIViewAnimationOptionRepeat);
// 1 1 0 0 0 & 1 0 0 0 = 0 1 0 0 0 = 8
// shouldRepeat = YES

The problem

The previous example of checking a bitmask might be a sufficient solution in cases where every option is represented by one bit. If the bitmask should change, this solution may become broken depending on the change!

This is even more obvious when we look at both the options for the animation curve and the animation transition. As you can see in the definition of these options, the shifting is different from the first options. Instead of shifting the value 1 by different steps, different values are shifted with the same amount of steps. These options will therefore end up using the same bits in the resulting bitmask. When this is the case, all bits in the mask that is dedicated to this option needs to be considered when determining if an option is present in a bitmask or not.

Lets look at an example where the check for an option done in the previous example is an insufficient solution.

UIViewAnimationOptions options = UIViewAnimationOptionCurveLinear;
// shifting value 3 (binary 11) 16 steps
// options = 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 = 196608

UIViewAnimationOptions easeInOption = UIViewAnimationOptionCurveEaseIn;
// shifting value 1 (binary 1) 16 steps
// options = 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 = 65536

BOOL const curveIsEaseIn = (options & easeInOption);
// curveIsEaseIn = 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 & 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 = 65536
// curveIsEaseIn = YES

As you can see, when checking options against a bitmask like this can lead to an incorrect result. In my example the check says that the options contains ease in, which is not what I defined… It’s enough for the options to have one bit in common in order for the result to turn into something other than 0 (false). So what would be a more sufficient way of checking if the animation curve is of type “ease in”?

A sufficient check requires that you know how the enumerated type is defined. So whenever I want to define these kinds of options I also create a corresponding function to check for a value in an option mask. This is great since if the enumerated type needs to be changed later on, there is just one place to change the values, instead of everywhere in the app. It also makes the check a lot more readable.

Here is an example of a function that I would have added to check for an animation curve if I had options simillar to the UIViewAnimationOptions.

static inline BOOL UIViewAnimationOptionsHasAnimationCurve(UIViewAnimationOptions options, UIViewAnimationOptions curve) {
    // Shift the options back 16 steps.
    // Then mask out other bits that are not used for the curve options.
    options = (options >> 16) & 3;
    // The same principle on the curve passed to the function
    curve = (curve >> 16) & 3;
    // Options and curve should now resolve to the same value if the curve is in the options mask
    return options == curve;
}

UIViewAnimationOptions options = UIViewAnimationOptionCurveLinear;
BOOL hasEaseInAnimationCurve = UIViewAnimationOptionsHasAnimationCurve(options, UIViewAnimationOptionCurveEaseIn);
// hasEaseInAnimationCurve = NO

The decimal value 3 is used in the example above since it’s binary representation is 11. Meaning that the two bits used for the animation curve will be kept, but other bits will be and-ed out by zeros.

As a practice for you, I leave the function for checking for a specific transition out. I hope you found this article interesting and that you gained some new insights. Happy coding!

Map, Filter, Flatmap and Reduce in Swift

Posted Aug 15, 2015

Last year at WWDC, Apple released their new programming language, Swift. The development of the language has progressed real quick since the release, and by now Swift 2 is in Beta and available to developers through Apples Developer Portal. The release has been a great success and Swift has become one of the most beloved programming languages out there! As a twist, the language is also expected to be released as open-source this fall.

While the language makes it easier for developers to write code with greater expressiveness, readability, security and performance - It also marks a bigger interest in alternative programming paradigms. While Apples old programming language, Objective-C, is a C-based, object-oriented programming language - Swift could be categorized as a multi-paradigm language. The language is still strongly object-oriented, but Apple has also added support to use Swift in a more functional fashion. This is done by adapting some of the most well-known functional concepts and encurage the use of immutable objects.

Functional approaches has some great benefits over the object-oriented once; especially when it comes to concurrency and thread-safety. They also tends to be simpler to put under test since all functions are fully centered around input and output data of the function, and does not depend on global states or cause any side-effects.

I want to start by making a run-through on some of the higher-order functions, with their origins in functional programming languages, that has been added to Swift. These are; Map, Filter, Flatmap and Reduce. In Swift 2.0 these methods has been moved from a global scope into the CollectionType protocol.

Map

func map<T>(@noescape _ transform: (Self.Generator.Element) -> T) -> [T]

This is the function definition of the map function in Swift. At a first glimpse this might look a bit scary, but lets break it down! func map declares the function map. The <T> part tells Swift that the type T is a placeholder for a class. This is known as a generic declaration. Declarations like this will stop the compiler from trying to look up the type T later in the declaration.

@noescape is an attribute in Swift that are used to communicate to the user of the function that the argument will not outlive the lifetime of the call. If the function dispatches to a different thread, an argument may be captured so that it exist at a later time when its needed. The @noescape attribute is a sign that this will not happen for this function.

The _ means that the external parameter name is not needed when calling the function. transform is the name of the parameter.

The type of the parameter is declared as (Self.Generator.Element) -> T. This is a closure that takes an argument of type Self.Generator.Element and returns an instance of type T. I will not explore SequenceType, GeneratorType etc. any further in this post, but for sake of clarity you can look at the Self.Generator.Element type as the same type of object as the type contained in the collection.

And finally -> [T] declares the return type of map. An array of T’s.

What map does is that it takes the given closure and call that on every element in the collection. As we can understand by the function declaration, the result of the map function is an array of the same type as the return type of the closure. So the result will be a new array but with elements that are the result of calling the closure on the elements in the origin array. Note that Self.Generator.Type is the type of the argument to the closure, but T is the return type. This means that the new array don’t necessarily need to contain objects of the same type as the origin array.

Here is an example on how it can be used in Swift.

let devices = ["Phone", "Pad", "Mac"]
var prefixedDevices: [String] = devices.map {
    (let device) -> String in
    return "i" + device
}
// prefixedDevices = ["iPhone", "iPad", "iMac"]

// Or similar...
prefixedDevices = devices.map { "i" + $0 }
// prefixedDevices = ["iPhone", "iPad", "iMac"]

For illustrating purposes here is how to achieve the same thing in Objective-C.

NSArray *devices = @[@"Phone", @"Pad", @"Mac"];
NSMutableArray *transformedDevices = [NSMutableArray arrayWithCapacity:[devices count]];
for (NSString *device in devices) {
    NSString *transformedDevice = [@"i" stringByAppendingString:device];
    [transformedDevices addObject:transformedDevice];
}
NSArray *prefixedDevices = [transformedDevices copy];
// prefixedDevices = @["iPhone", "iPad", "iMac"]

Filter

public func filter(@noescape includeElement: (Self.Generator.Element) -> Bool) -> [Self.Generator.Element]

Filter is a bit different from map in its declaration. The type of the includeElement parameter is a closure that takes a Self.Generator.Element and returns a boolean value. The return type of filter is also an array of the same type as the argument to the closure; Self.Generator.Element. What this means is that the resulting array will be an array with objects of the same type as the origin array.

The filter function calls the closure on every element, and if the closure returns True, then the element will be included in the new array.

let devices: [String] = ["iPhone", "Samsung Galaxy", "iPad"]
var filteredDevices = devices.filter {
    (let device) -> Bool in
    return device[device.startIndex] == "i"
}
// filteredDevices = ["iPhone", "iPad"]

// Or similiar...
filteredDevices = devices.filter { $0[$0.startIndex] == "i" }
// filteredDevices = ["iPhone", "iPad"]

And again - Here is the same thing done in Objective-C.

NSArray *devices = @[ @"iPhone", @"Samsung Galaxy", @"iPad" ];
NSMutableArray *mutableFilteredDevices = [NSMutableArray arrayWithCapacity:[devices count]];
for (NSString *device in devices) {
    NSString *firstLetter = [device substringToIndex:1];
    if ([firstLetter isEqualToString:@"i"]) {
        [mutableFilteredDevices addObject:device];
    }
}
NSArray *filteredDevices = [mutableFilteredDevices copy];
// filteredDevices = @["iPhone", "iPad"]

Flatmap

public func flatMap<S : SequenceType>(@noescape transform: (Self.Generator.Element) -> S) -> [S.Generator.Element]

Now, flatMap can be a bit harder to wrap your head around at first. Lets have a short break down of the declaration.

A generic declaration <S : SequenceType> is used for referring a type that conforms to the SequenceType protocol. The argument for parameter transform should be a closure that takes an element in the collection which the flatMap function is called on, and return an object conforming to SequenceType. The return type of the flatMap function is then declared to be an array with objects of the same type as the closure argument.

FlatMap is handy to use when you are working with multi-dimensional arrays. Just like the map function the transform closure gets an element in the collection as argument, but the flatMap closure is expected to return a type conforming to SequenceType (eg. Array). What flatMap then does is that it flattens all these returned sequences and return that as an array.

let shoppingBags = [["Banana", "Apple", "Orange"], ["Cornflakes"], ["Coffee", "Butter"]]
var shoppingBag = shoppingBags.flatMap {
    (let shoppingBag) -> [String] in
    return shoppingBag
}
// shoppingBag = [Banana, Apple, Orange, Cornflakes, Coffee, Butter]

// Or simillar...
shoppingBag = shoppingBags.flatMap { $0 }
// shoppingBag = [Banana, Apple, Orange, Cornflakes, Coffee, Butter]

So flatmap can help you remove a dimension in your array. You can of course do more things than just returning the array passed to the closure. I would say that flatmap is most powerful together with other higher-order functions. Here are some other use-cases.

let shoppingBags = [["Banana", "Apple", "Chocolate"], ["Cornflakes", "Chocolate"], ["Coffee", "Butter"]]
let numberOfItemsInBags = shoppingBags.flatMap { [$0.count] }
// numberOfItemsInBags = [3, 2, 2]

let healthierShoppingBag = shoppingBags.flatMap {
    return $0.filter {
        $0 != "Chocolate"
    }
}
// healtherShoppingBag =  [Banana, Apple, Cornflakes, Coffee, Butter]

let persons = [["id": 1, "age": 30], ["id": 2, "age": 24], ["id": 3, "age": 36]]
let agesPlusOne = persons.flatMap { $0["age"] }.map { $0 + 1 }
// agesPlusOne = [31, 25, 37]

Reduce

func reduce<T>(initial: T, @noescape combine: (T, Self.Generator.Element) -> T) -> T

At last! Lets take a closer look at the reduce function and its declaration. A generic declaration is specified, T. Reduce has two parameters. First initial, an object of type T. Then the combine parameter which takes a closure as argument. The closure in turn takes an object of type T and an element in the collection the reduce function is called on as arguments. The closure should return an object of the same type as the first parameter. The return value of the reduce function is of type T.

The problem the reduce function solves is that it combines all elements in the collection into one single value. While the closure is called on every element in the collection, the initial argument to the closure will be the returned value from the closure for the previous element. The first element in the collection will have the initial argument to the reduce function as the inital argument to the closure. The returned value of the reduce function is the same value as returned from the closure when called on the last element.

let ages = [10, 21, 24, 53]
var sumOfAges = ages.reduce(0) {
    (let initial, let element) -> Int in
    return initial + element
}
// sumOfAges = 108

// Since operators are functions we can do..
sumOfAges = ages.reduce(0, combine: +)
// sumOfAges = 108

Here is the same thing done in Objective-C.

NSArray *ages = @[@(10), @(21), @(24), @(53)];
NSNumber *sumOfAges = @(0);
for (NSNumber *age in ages) {
    sumOfAges = @([sumOfAges integerValue] + [age integerValue]);
}
// sumOfAges = 108

// Or using collection operators
sumOfAges = [ages valueForKeyPath:@"@sum.self"];
// sumOfAges = 108

Of course reduce is not limited to numbers. It can be used with any data type that you can combine into a single value inside the closure.

Conclusion

All these higher-order functions added to Swift can be really powerful, especially when chained with each other. I look forward into discover more of the functional programming concepts added to Swift, and getting used to use them effectively! I think that when you get into the mindset and get comfortable using these methods - You will probably change how you tackle those everyday programming tasks.