Tuple vs Struct in Swift

I don't know if anyone is still interested in this but sometimes i use tuples like this to keep things organised and it seems more readable to me.

struct SystemState{
    let someSetting: Int
    let someChoice: Int
    let howmuchDoYouNeedForAnExample: String
}

struct UserState{
    let name: String
    let email: String
    let accessLevel: Int
    let blablabla:[String:String]
}

Given the above might be defined somewhere else:

typealias State = (system: SystemState,user: UserState)

let theSystemState = SystemState(someSetting: v1, someChoice: v2,
     howmuchDoYouNeedForAnExample: v3)
let theUserState = theSystemState,UserState(name: v4, email: v5, 
    accessLevel: v6, blablabla: v7)


var state: State = (theSystemState,theUserState)

members are now accessed like this. It looks just the same as structs.

    state.system.someSetting
    state.user.accessLevel

As far as i can tell there is no real difference between using structs or tuples just the advantages mentioned in the accepted answer by dfri. Tuples also offer simplicity when you just want pass around something that is easier to keep together but has no need, or conceptually makes no sense, to be encapsulated in a struct. This way your code documents your intention in some small way that might make it easier to understand in the future for you or someone else.


This question of a slightly "discussion" nature, but I'll add two points in favour of sometimes preferring tuples over structures.


Native Equatable conformance for limited sized tuples

In Swift 2.2, tuples of up to size 6 will be natively equatable, given that it's members are equatable

  • Proposal SE-0015: Tuple comparison operators

This means tuples will sometimes be the natural choice over using smaller constructs in a limited scope.

E.g. consider the following example, using (1): a structure

struct Foo {
    var a : Int = 1
    var b : Double = 2.0
    var c : String = "3"
}

var a = Foo()
var b = Foo()

// a == b // error, Foo not Equatable

/* we can naturally fix this by conforming Foo to Equatable,
   but this needs a custom fix and is not as versatile as just 
   using a tuple instead. For some situations, the latter will
   suffice, and is to prefer.                                  */
func == (lhs: Foo, rhs: Foo) -> Bool {
    return lhs.a == rhs.a && lhs.b == rhs.b && lhs.c == rhs.c
}

and (2): a tuple

/* This will be native in Swift 2.2 */
@warn_unused_result
public func == <A: Equatable, B: Equatable, C: Equatable>(lhs: (A,B,C), rhs: (A,B,C)) -> Bool {
    return lhs.0 == rhs.0 && lhs.1 == rhs.1 && lhs.2 == rhs.2
}
/* end of native part ...           */

var aa = (1, 2.0, "3")
var bb = (1, 2.0, "3")

aa == bb // true
aa.0 = 2
aa == bb // false

Generic access to different type tuples: more versatile than for different type structures

From the above (compare the == functions) it's also apparent that tuples are easily to work with in the context of generics, as we can access their anonymous member properties using the .0, .1 ... suffixes; whereas for a struct, the easiest way to mimic this behaviour quickly becomes quite complex, needing tools such as runtime introspection and so on, see e.g. this.