By Paul Cantrell


2015-10-25 17:19:47 8 Comments

I would like extend Array to add conformance to a new protocol — but only for arrays whose elements themselves conform to a specific protocol.

More generally, I’d like to have types (whether protocols or concrete types) with type parameters implement a protocol only when the type parameters match certain constraints.

As of Swift 2.0, this appears to be impossible. Is there a way I’m missing?

Example

Suppose we have the Friendly protocol:

protocol Friendly {
    func sayHi()
}

We can extend existing types to implement it:

extension String: Friendly {
    func sayHi() {
        print("Greetings from \(self)!")
    }
}

"Sally".sayHi()

We can also extend Array to implement sayHi() when its elements are all Friendly:

extension Array where Element: Friendly {
    func sayHi() {
        for elem in self {
            elem.sayHi()
        }
    }
}

["Sally", "Fred"].sayHi()

At this point, the type [Friendly] should itself implement Friendly, since it meets the protocol’s requirements. However, this code doesn’t compile:

extension Array: Friendly where Element: Friendly {
    func sayHi() {
        for elem in self {
            elem.sayHi()
        }
    }
}

The error message is “extension of type 'Array' with constraints cannot have an inheritance clause,” which seems to shut the door definitively on that direct approach.

Is there an indirect workaround? Some clever trick I can use? Perhaps there’s a way that involves extending SequenceType instead of Array?

A working solution would make this code compile:

let friendly: Friendly = ["Foo", "Bar"]

Update: This has landed in Swift 4.1, and it is a thing of beauty!

The extension Array: Friendly where Element: Friendly example now compiles as given in the original question.

2 comments

@Rob Napier 2015-10-25 18:18:01

EDIT: As noted in the updated question, this is now possible since Swift 4.1


This is not currently possible in Swift (as of Xcode 7.1). As the error indicates, you can't restrict protocol conformance ("inheritance clause") to a type-constrained extension. Maybe someday. I don't believe there's any deep reason for this to be impossible, but it's currently not implemented.

The closest you can get is to create a wrapper type such as:

struct FriendlyArray<Element: Friendly>: Friendly {
    let array: [Element]
    init(_ array: [Element]) {
        self.array = array
    }
    func sayHi() {
        for elem in array {
            elem.sayHi()
        }
    }
}

let friendly: Friendly = FriendlyArray(["Foo", "Bar"])

(You would likely want to extend FriendlyArray to be a CollectionType.)

For a tale of my own descent into the madness of trying to make this work, and my crawl back from the edge, see NSData, My Old Friend.

@Paul Cantrell 2015-10-25 19:12:13

The struct wrapper seems to be the go-to solution for lots of things where Swift generics break down. For example, witness the API methods returning AnySequence because they can’t return SequenceType….

@fabb 2016-08-11 07:28:33

@Zigii Wong 2016-10-30 12:52:02

@Phil Mitchell 2017-12-11 18:24:29

It didn't make it into Swift 4 but it appears to be under active development. (See link on prev comment)

@Paul Robinson 2018-01-09 18:31:29

The good news is that what you are asking for Conditional Conformance is coming in Swift 4.1:

https://swift.org/blog/conditional-conformance/

Related Questions

Sponsored Content

10 Answered Questions

[SOLVED] How can I extend typed Arrays in Swift?

  • 2014-06-04 00:26:14
  • mythz
  • 72407 View
  • 198 Score
  • 10 Answer
  • Tags:   arrays swift

1 Answered Questions

[SOLVED] Can you have protocol extension for a specific generics type in Swift?

  • 2016-02-10 11:54:23
  • Mecki
  • 894 View
  • 2 Score
  • 1 Answer
  • Tags:   swift protocols

7 Answered Questions

4 Answered Questions

[SOLVED] Define a Swift protocol which requires a specific type of sequence

1 Answered Questions

[SOLVED] Swift protocol conformance with associated type using same-type constraint

  • 2017-12-19 08:34:17
  • Werner Altewischer
  • 939 View
  • 3 Score
  • 1 Answer
  • Tags:   swift swift4

6 Answered Questions

[SOLVED] Extend array types using where clause in Swift

2 Answered Questions

[SOLVED] Can't create an Array of types conforming to a Protocol in Swift

Sponsored Content