21

I'd like to write an extension for tuples of (e.g.) two value in Swift. For instance, I'd like to write this swap method:

let t = (1, "one")
let s = t.swap

such that s would be of type (String, Int) with value ("one", 1). (I know I can very easily implement a swap(t) function instead, but that's not what I'm interested in.)

Can I do this? I cannot seem to write the proper type name in the extension declaration.

Additionally, and I suppose the answer is the same, can I make a 2-tuple adopt a given protocol?

Jean-Philippe Pellet
  • 59,296
  • 21
  • 173
  • 234
  • 1
    The [Swift documentation for Types](https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Types.html) distuingishes between *named types* and *compound types*. Named types can be extended, but tuples (and functions) are compound types. – Martin R Feb 04 '15 at 09:41
  • Thanks, Martin. Looks like this is a definite “no”, then. Can you turn it into an answer so that I can accept it? – Jean-Philippe Pellet Feb 04 '15 at 09:47
  • The most customisation you can do with Tuples is naming the parameters and using a `typealias` for it. For anything more complex you should use `struct`s or define global functions (maybe with generics) – DeFrenZ Feb 04 '15 at 12:22
  • man... it would be mindblowing to be able to define extensions on typealiases... I am ready to accept enforcing of some kind like (use the same naming as declared in the tuple or whatever)... – Fawkes Oct 07 '15 at 20:37

4 Answers4

38

You cannot extend tuple types in Swift. According to Types, there are named types (which can be extended) and compound types. Tuples and functions are compound types.

See also (emphasis added):

Extensions
Extensions add new functionality to an existing class, structure, or enumeration type.

Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
6

As the answer above states, you cannot extend tuples in Swift. However, rather than just give you a no, what you can do is box the tuple inside a class, struct or enum and extend that.

struct TupleStruct {
    var value: (Int, Int)
}
extension TupleStruct : Hashable {
    var hashValue: Int {
        return hash()
    }
    func hash() -> Int {
        var hash = 23
        hash = hash &* 31 &+ value.0
        return hash &* 31 &+ value.1
    }
}

func ==(lhs: TupleStruct, rhs: TupleStruct) -> Bool {
    return lhs.value == rhs.value
}

As a side note, in Swift 2.2, tuples with up to 6 members are now Equatable.

M. Mayer
  • 133
  • 1
  • 7
0

Details

  • Xcode 11.2.1 (11B500), Swift 5.1

Solution

struct Tuple<T> {
    let original: T
    private let array: [Mirror.Child]
    init(_ value: T) {
        self.original = value
        array = Array(Mirror(reflecting: original).children)
    }

    func getAllValues() -> [Any] { array.compactMap { $0.value } }
    func swap() -> (Any?, Any?)? {
        if array.count == 2 { return (array[1].value, array[0].value) }
        return nil
    }
}

Usage

let x = (1, "one")
let tuple = Tuple(x)
print(x)                                        // (1, "one")
print(tuple.swap())                             // Optional((Optional("one"), Optional(1)))
if let value = tuple.swap() as? (String, Int) {
    print("\(value) | \(type(of: value))")      // ("one", 1) | (String, Int)
}
Vasily Bodnarchuk
  • 24,482
  • 9
  • 132
  • 127
0

If you wanted to be a Bad Person™ you can define custom operators on tuples, like this:

postfix operator <->

postfix func <-> <A, B>(lhs: (A, B)) -> (B, A) {
    return (lhs.1, lhs.0)
}

let initial = (1, "one")
let reversed = initial<->

FWIW I can't think of a place where my 'clever' code trumps the readability of just writing your swap function.

deanWombourne
  • 38,189
  • 13
  • 98
  • 110