the Reverend
the Reverend

Reputation: 12559

Extend Array constrained when Element is a tuple

Is there a way to extend an Array when the element is a type of tuple ?

public extension Array where Element: (timeZoneName: String, formattedName: String){

}

This declaration returns 4 errors:

  • Statement cannot begin with a closure expression
  • Braced block statements is an unused closure
  • Expected '{' in extension
  • Expected identifier for type name

I can't tell if the errors shown are accurate. Any ideas?

Upvotes: 5

Views: 2112

Answers (4)

J.Wang
J.Wang

Reputation: 1236

It's now possible in Swift 3.1.

extension Array where Element == (String, String) {
    ...
}

Upvotes: 4

Artem Novichkov
Artem Novichkov

Reputation: 2341

Swift 3 version of appzYourLife's answer:

extension Sequence where Iterator.Element == Tuple2 {
    func foo() {}
}

Upvotes: 4

timbo
timbo

Reputation: 14334

You can't add specific typing like extension Array where Element == Int because this would transform the generic Array into a non-generic version.

You will see an error something like same-type requirement makes generic parameter 'Element' non-generic

Edit

It does actually seem legit (at least in Swift 2.2) to do:

typealias tzTuple = (timeZoneName: String, formattedName: String)

extension Array where Element: tzTuple  {

}

You will have to see if this works in runtime though.

I was checking this in a Playground and at present, Playgrounds are not yet fully functional with Swift 2.2-dev

I would suggest this instead:

typealias tzTuple = (timeZoneName: String, formattedName: String)

extension Array {

  func formattedName(index: Int) -> String? {
    if self[index] is tzTuple {
      return (self[index] as! tzTuple).formattedName
    }
    return nil
  }
}

will allow you to do

let foo = [(timezoneName: "PST", formattedName: "Pacific Standard Time"),(timezoneName: "AEST", formattedName: "Australian Eastern Time")]
print(foo.formattedName(0))

Upvotes: 1

Luca Angeletti
Luca Angeletti

Reputation: 59506

Since (AFAIK) the Tuple type does not conform to a Protocol (and does not even have a name) it's very hard to do what you need.

This is the closest I could get (maybe others can provide more elegant solutions).

Typealias

First of all lets define a couple of typealiases

typealias Tuple2 = (Any, Any)
typealias Tuple3 = (Any, Any, Any)

Yes, some readers now understand where I am going and probably don't like it...

I don't like it neither

SequenceType

Now let's extend the protocol SequenceType adding the foo method when the Element of the sequence is Tuple2...

extension SequenceType where Generator.Element == Tuple2 {
    func foo() {}
}

or Tuple3

extension SequenceType where Generator.Element == Tuple3 {
    func foo() {}
}

Array

Next lets define and populate an array of Tuple2

let list: [Tuple2] = [(1,2)]

Now the extension is applied and we can write

list.foo()

Disclaimer :D

This does work only if the array is explicitly declared as [Tuple2] (or [Tuple3]).

Something like this does not work

let list = [(1,2)]
list.foo() // compile error

Upvotes: 3

Related Questions