Protocol extensions and the death of the pipe-forward operator

So a while back I wrote about using some functional programming techniques in Swift to solve the Luhn credit card checksum problem.

One of the suggestions in the article was defining and using |> to avoid the annoying tennis-match bouncing left and right between free functions and methods.

Since 2.0 came out, I’ve been thinking I really needed to update some of my articles to the new syntax, and started on this one. Except as protocol extensions are the new hotness, using them would probably be the more “Swift-y” way of writing this. So here’s a solution using new 2.0 features.

As a reminder, here’s the requirements, in the form of wikipedia’s description of the algorithm:

  1. From the rightmost digit, which is the check digit, moving left, double the value of every second digit; if the product of this doubling operation is greater than 9 (e.g., 8 × 2 = 16), then sum the digits of the products (e.g., 16: 1 + 6 = 7, 18: 1 + 8 = 9).
  2. Take the sum of all the digits.
  3. If the total modulo 10 is equal to 0 (if the total ends in zero) then the number is valid according to the Luhn formula; else it is not valid.

So, here in turn are each of the components, all written as extensions.

First, converting characters to integers. Similar to String.toInteger becoming Int.init(String), here’s an extension of Int:

extension Int {
    init?(c: Character) {
        guard let i = Int(String(c)) else { return nil }

        self = i

Here I’m using guard to check the value is convertible and return nil if not. Yes, I know, this is hardly different from an if let/else, but I like the use of guard whenever I want to handle a failure case like this “up front”.

It would be nice to make this a protocol extension rather than an extension of Int. All the std lib integer types support a from-string initializer, after all. But this would involve creating a protocol like IntegerStringConvertible and then extending all the integers to conform to it, since such a common grouping doesn’t exist.

The previous post defined mapSome, which takes a transformation function that returns an optional, and returns an array of only those values that weren’t transformed into nil:

extension SequenceType {
    func mapSome<U>(transform: Generator.Element -> U?) -> [U] {
        var result: [U] = []
        for case let x? in lazy(self).map(transform) {
        return result

(the for case let x? is using the new pattern-matching syntax that lets you for over only the non-nil values in a sequence)

But as of 2.0, flatMap has been enhanced to do this exact thing. So we no longer need to define it.

We’re going to use this along with the character-to-integer initializer to extract only the numbers from the credit-card string, like so, using the new 2.0b2 feature of using an init as a function:

// returns [1,2,3,4,5,6]

(note, we have to do this on the .characters view now, since String is no longer itself a sequence).

Next, the a function that let you apply a transformation only to every n th value in a sequence:

extension SequenceType {
    func mapEveryNth(n: Int, transform: Generator.Element -> Generator.Element)
        -> [Generator.Element]  {

            // enumerate starts from zero, so for this to work with the nth element,
            // and not the 0th, n+1th etc, we need to add 1 to the ifIndex check:
            let isNth = { ($0 + 1) % n == 0 }

            return enumerate().map { i, x in
                isNth(i) ? transform(x) : x

Then, a sum on any sequence that contains integers:

extension SequenceType where Generator.Element: IntegerType {
    func sum() -> Generator.Element {
        return reduce(0, combine: +)

and an extension on any integer to check if it’s a multiple of another:

extension IntegerType {
    func isMultipleOf(of: Self) -> Bool {
        return self % of == 0

And finally, to put them all together into a single extension to String that validates the checksum:

extension String {
    func luhnchecksum() -> Bool {
        return characters
            .mapEveryNth(2) { $0 < 5 ? $0*2 : $0*2 - 9 }

let ccnum = "4012 8888 8888 1881"
print( ccnum.luhnchecksum() ? "👍" : "👎" )

This now looks very similar to the version that used the |> operator – but without having to define any custom operator at all. Which feels like a win to me.

Yes, you could have done all this before using extensions of concrete objects in 1.2. But most of these extensions are more general than that – for example, mapSome can work on the string character view, but also arrays, dictionaries, sets.

Anyway, now back to playing with beta 2…

Changes to the Swift Standard Library in 2.0 beta 1

OK don’t panic – it might look like a lot has changed, but not really. It’s more… transformed. For the better. Nothing the migration assistant shouldn’t be able to handle.

By far the biggest change in the standard library is due to the new protocol extensions. The free map function is dead, long live the map extensions to CollectionType and SequenceType. Which means now you only ever call map as a method – no more shuttling back and forth between functions and methods like you’re watching a tennis match.

To show how this works, let’s define my usual example, mapSome:

extension SequenceType {
    /// Return an `Array` containing the results of mapping `transform`
    /// over `self`, discarding any elements where the result is `nil`.
    /// - Complexity: O(N).
    func mapSome<U>(@noescape transform: Generator.Element -> U?) -> [U] {
        var result: [U] = []
        for case let x? in {
        return result

You can use this in the method-calling style, for example, with the brand new double-from-string failable initializer:

let a = ["3.14", "foo", "6.02e23"]
let doubles = a.mapSome { Double($0) }
print(doubles) // no more println!
// prints [3.14, 6.02e+23]

Incidentally, this implementation of mapSome uses the new pattern-matching capabilities of for to filter out nils. The case let syntax is matching an enumeration – and since optionals are enumerations, it works for them too. for has also acquired where clauses:1

let isEven = { $0%2 == 0 }
for even in 0..<10 where isEven(even) {

But there’s more. You can constrain the extension, similar to how you would constrain a placeholder in a generic function. And this means you can give protocols methods that only apply when they have certain properties. For example, there’s now a version of sort on arrays (or any other collection type) that doesn’t need to be given a isOrderedBefore argument, so long as the array contents are Comparable. There’s still an overload that takes a closure if you want to do something more custom, but if you just want the default behaviour (ascending), you don’t need one.

For example, here’s an implementation of all that returns true if all the values are equal to a certain value:

// a version that only applies when the contents of the
// sequence are equatable
extension SequenceType where Generator.Element: Equatable {
    /// Return `true` iff every element of `self` is `x`.
    func all(equalTo: Generator.Element) -> Bool {
        // of course, contains is now a method too
        return !self.contains { $0 != equalTo }

// and an unconstrained version where the caller supplies a predicate
extension SequenceType {
    /// Return `true` iff every element of `self` satisfies `predicate`.
    func all(criteria: Generator.Element -> Bool) -> Bool {
        return !self.contains { !criteria($0) }

[1,1,1].all(1)       // true

let isEven = { $0%2 == 0 }
[2,4,6].all(isEven)  // true

As a result, the number of free functions in the standard library has dropped from 101 down to 77. I wonder how far this will go – will it eventually just be a motly crew of unsafeBitCast and company left? Should abs() become an extension of SignedNumberType? And now it can be, should it be a property? This and more in the next exciting installment of Swift…

Grab Bag

Here are a few other changes to the standard library:

  • Array.withUnsafeMutableBufferPointer has acquired a warning: do not use the array itself while calling it, only refer to the contents via the pointer. Presumably so updates to the array can potentially be deferred to after it’s finished executing. Same for ContiguousArray and Slice.
  • They’ve also had some of their internal-type initializers privated.
  • Some of the _-prefixed protocols have started to disappear. For example _BidirectionalIndexType is gone, and BidirectionalIndexType now has its predecessor method. And _Comparable is gone, Comparable now containing its < operator.
  • CollectionOfOne and EmptyCollection now have a count property – just in case you want to check they’re not misleading you.
  • So now for the start of the great extensionizing… CollectionType now has isEmpty, count, map, filter, first, last, indexOf, indices and reverse. So these are now available as methods on all collections. Corresponding methods in existing collections have been removed.
  • indexOf is what find used to be called. And it now has a version that takes a predicate.
  • An ErrorType protocol has been added to support the new error handling feature.
  • Printable and DebugPrintable protocols are now the more descriptive CustomStringConvertible and CustomDebugStringConvertible
  • There are also CustomReflectable, CustomLeafReflectable and CustomPlaygroundQuickLookable protocols for tweaking how your type behaves in a playground.
  • And there’s a new Mirror type for returning from the CustomReflectable protocol.
  • There’s a new DictionaryLiteral type, so you can now use the [:] syntax for more than just dictionaries without worrying about duplicate keys getting coalesced.
  • As mentioned above, Double, Float and Float80 have acquired failable initializers from strings.
  • And the integers now have the same, replacing the toInt method on string. And they take a radix argument! You still can’t tell from the headers what default values are for defaulted arguments, but I'm guessing this one is 10.
  • FloatingPointType’s _toBitPattern and _fromBitPattern are gone. I guess you can use unsafeBitCast if you like bits.
  • All the lazy collections have acquired an underestimateCount.
  • MutableCollectionType is a good example of extensions with where clauses – such as requiring the collection also be random-access in order for it to have partition and sortInPlace support.
  • SequenceType sucks in contains, sort, underestimateCount, enumerate, minElement, maxElement, elementsEqual, lexicographicalCompare and flatMap
  • elementsEqual being the new name for the equal function that compares two sequences.
  • and minElement and maxElement now return optionals in case of empty sequences, and also now have versions that take isOrderedBefore closures.
  • There’s a new SetAlgebraType protocol, for types that are “a generalized set whose distinct elements are not necessarily disjoint”. Set does not conform to it (though it has all the properties it requires).
  • A type that does conform to it is OptionSetType protocol, for bitfield enums.
  • print is gone! Now println is print and old print is print(1, newLine: false)
  • toString is no more. Just use the String initializer that takes any type (and has a similar hierarchy of fallbacks)
  • readLine reads from the standard input, returning an optional String so you can while let over it.

Protocol Extensions are Defaults

Silly jokes aside, there’s a good reason for why CollectionOfOne and EmptyCollection have implementations of count. If a protocol has a default implementation, but you know your specific type can do it faster because of how it works internally, a specific implementation will take precedence over the protocol version.

So for example, suppose we implemented the next (but fairly pointless) logical collection type: CollectionOfTwo:

struct CollectionOfTwo<T>: CollectionType {
    let first: T, second: T
    subscript(idx: Int) -> T {
        precondition(idx < 2, "Index out of bounds")
        return idx == 0 ? first : second
    var startIndex: Int { return 0 }
    var endIndex: Int { return 2 }

let two = CollectionOfTwo(first: "42", second: "420")
",".join(two)  // “42,420"

Notice, that I didn’t need to define a generator at all – due to this handy new protocol extension:

// CollectionType conforms to _CollectionGeneratorDefaultsType 
// which is extended with:
extension _CollectionGeneratorDefaultsType { 
    func generate() -> IndexingGenerator<Self>

Anyway because CollectionOfTwo conforms to CollectionType it gets a count property for free. But it gets them by subtracting the end index from the start, which is quite a roundabout way of doing it. So you can instead give it a hardcoded value by explicitly implementing it:

extension CollectionOfTwo {
    var count: Int { return 2 }

Now, when count is called, it will run this code instead of the default.

Protocols can also replace the default implementations of other protocols they conform to – hence CollectionType defines map even though SequenceType does too.

While we’re implementing simple little types – the default string rendering of custom types is now a lot nicer. Even though it doesn’t yet conform to CustomStringConvertible, if you print out CollectionOfTwo you’ll get something that looks like CollectionOfTwo(first: 42, second: 420) which is much nicer that the __lldb_expr_11.CollectionOfTwo you used to get.

Strings are No Longer Collections

Something that might take you by surprise – String no longer conforms to CollectionType. Though it has all the required properties (just writing extension String: CollectionType { } without any implementation works), it’s no longer tagged as such. This is apparently due to concerns that, even with the Character representation, there were ways in which using collection algorithms on strings could produce non-Unicode-correct results.

Of course, you still need to manipulate strings, so rather than just resorting to staring at them extra intensely, you can use the new CharacterView accessible via the characters property:

let s = "comma,separated,strings"
let fields = split(s.characters) { $0 == "," }.map { String($0) }

Since String's Index is just a typealias for String.CharacterView.Index, you can use them interchangeably:

let s = "Hello, world!"
if let comma = s.characters.indexOf(",") {

Nonetheless, the fact that you have to switch to a character-based view on the string rather than operate on it directly should act as a reminder that you might be doing something that doesn’t behave correctly under all edge cases.

Type-Erased Containers

Finally, there are now a collection of “type-erased” container types available: AnyBidirectionalCollection, AnyRandomAccessCollection and AnyForwardCollection (and associated indexes), plus AnyGenerator and AnySequence. These could be used, for example, to bully different kinds of collection into being in the same container:

let set: Set = [1,2,3]
let array = [4,5,6]
let anySet = AnyForwardCollection(set)
let anyArray = AnyForwardCollection(array)
let anys = [anySet,anyArray]
anys.flatMap { $0 } // [2, 3, 1, 4, 5, 6]

However, this is probably not all that useful. Despite the name, this isn’t like the Any type – you can’t cast back into the original type, it’s more a one-way trip.

This is more useful when you want to expose an internal collection without exposing exactly what that collection type is. Instead you could create an AnyXXXCollection from your internal value, and return that, safe in the knowledge users of your class won’t complain when you switch to a different internal data structure later on.

Well that’s it. The standard library has some sparkly new online documentation. And as part of the WWDC sample code, there’s a playground all about the Swift standard library that is worth checking out. Also it looks like the developer forums for Swift no longer require a developer login to read either, if you want to take a look without registering.

Here’s to a future using all this stuff on the back end once the port to Linux is available!

  1. Of course, you wouldn’t write this would you – you’d write for even in stride(from: 0, to: 10, by: 2), right?