Swift blog: Wrangling protocols

The app I’m working on has a set of interesting requirements on the data layer.

Let’s try to break it down: I have a set of data that can be represented on 2 different ways, although is the same type of data.

My Protocol-Oriented-Programming training kicked in:

protocol CriteriaItem {
	var title: String { get set }
struct SingleCriteriaItem: CriteriaItem {
	var title: String
struct MultipleCriteriaItem: CriteriaItem {
	var title: String

I want to handle every item as a CriteriaItem, regardless it being Multiple or Single.

The server spits a set of strings, which then need to be converted to CriteriaItems:

let criteriaItemTitles = ["One", "Two", "Three", "Two"]
let criteriaItems: [CriteriaItem] = criteriaItemTitles.map { SingleCriteriaItem(title: $0) }

Now, let’s define a function to filter an array to get only unique values from it:

func uniq<S:SequenceType, E: Hashable where E == S.Generator.Element>(source: S) -> [E] {
    var seen: [E:Bool] = [:]
    return source.filter { v -> Bool in
        return seen.updateValue(true, forKey: v) == nil
// uniq([1, 3, 2, 3, 2]) # => [1, 3, 2]

Great, so now we’re ready to get only an array of unique CriteriaItems:

let uniqueItems = uniq(criteriaItems)
# ERROR: Cannot invoke `uniq` with an argument list of type `([CriteriaItem])`

If we check the type constraints on the generic uniq function, we know that:

  1. uniq is generic on S and E
  2. S, which is the parameter passed to the function, needs to be a SequenceType-conforming type.
  3. The Element on the sequence’s Generator should be the same type as E, the function’s output type.
  4. E, which is the output type of the function, should be Hashable.

Lets verify what we have:

  1. Arrays on Swift conform to CollectionType which inherits from SequenceType, so our criteriaItems constant is good ([CriteriaItem]).
  2. We expect an array of CriteriaItems as the function’s output, so we comply with the 3rd point.
  3. CriteriaItem is a protocol, and today you can’t make a protocol type conform to another protocol.

The solution: wrap the protocol on a struct that conforms to Hashable:

struct BoxedItem: Hashable {
	let item: CriteriaItem
	var hashValue: Int {
		return item.title.hashValue
func ==(lhs: BoxedItem, rhs: BoxedItem) -> Bool {
	return lhs.hashValue == rhs.hashValue

So, now, to be able to extract only the unique CriteriaItems, we need to wrap every one of them in a box:

let boxedItems = criteriaItems.map { BoxedItem(item: $0) }
let uniqueItems = uniq(boxedItems).map { $0.item } // 3 => [{title "One"}, {title "Two"}, {title "Three"}]


There seems to be a bug with Swift, were the compiler won’t be able to infer the type of a collection of protocol implementations:

protocol A {
	var a: String { get set }
struct X: A {
	var a: String
func takesAs(aas: [A]) {
	// Something
let letters = ["A", "B", "C", "D"]
let xs = letters.map { X(a: $0) } // xs is of type [X]
takesAs(xs) // Cannot convert value of type `[X]` to expected argument type `[A]`
let xs2: [A] = letters.map { X(a: $0) } // xs2 is casted to type [A]
takesAs(xs2) // Works as expected

However, passing a protocol-comforming type instance alone works as expected:

func takesA(a: A) {
	// Something
let x = X(a: "A")
takesA(x) // Works as expected

This was reported to Apple as rdar://23499056.

Did I miss something or want to share some insight on this post? [Drop me a line.](mailto:oscar@swanros.com?subject=Swift blog 1)

Esta entrada fue publicada en Uncategorized y etiquetada , , . Enlace permanente.