Can I extend Tuples in Swift?
Asked Answered
C

4

23

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?

Cupboard answered 4/2, 2015 at 9:18 Comment(4)
The Swift documentation for Types distuingishes between named types and compound types. Named types can be extended, but tuples (and functions) are compound types.Solano
Thanks, Martin. Looks like this is a definite “no”, then. Can you turn it into an answer so that I can accept it?Cupboard
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 structs or define global functions (maybe with generics)Neukam
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)...Orgell
S
41

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.

Solano answered 4/2, 2015 at 9:55 Comment(0)
P
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.

Plumy answered 20/6, 2016 at 13:46 Comment(0)
S
2

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.

Saskatchewan answered 9/11, 2022 at 11:49 Comment(1)
That is awful :D I need to add that to my ”horrible operator hacks in Swift” document.Olives
C
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)
}
Compilation answered 15/11, 2019 at 3:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.