Tuple vs Struct in Swift
Asked Answered
C

3

19

I understand that Swift's tuples serve, for example, as a simple way for a function to return multiple values. However, beyond this "simplicity aspect", I don't see very well any necessity of using tuples instead of structs.

Therefore, my question: in terms of design, is there any scenario where tuples are clearly a better choice than structs?

Cystectomy answered 2/2, 2016 at 12:43 Comment(2)
I would say myself that tuples are only useful for data structures that are used only locally; that otherwise it is better to have all data structures properly defined and "labeled" as structs or classes, instead of having them "floating around as anonymous tuples". But I am just not sure I wouldn't be wrong...Cystectomy
I think the simplicity aspect is what it's all about:) No need to define a struct, less code, quick. Swift has many features that serve the purpose of simplicity.Croatia
E
11

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

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.

Environs answered 2/2, 2016 at 13:1 Comment(2)
That's interesting. Thank youCystectomy
Tuples in function params and returns can make it really clear what the function will do. func multiply(aNumber number : Int, by anotherNumber : Int) -> Int. As a struct this would not be clear at all. func multiply(twoNumbers : TwoNumbersStruct) -> IntGrogshop
C
3

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.

Chokecherry answered 10/4, 2020 at 4:41 Comment(0)
U
0

Consider this, java to objective-C. When you have to plug yourself to this type of datasource in your project (because you have a huge basecode in android and don't want or cannot do everything from scratch), you find yourself with java types datasource (like hashmap for example), those are basically typedef from objective-c types. This is not easily plugable in swift depending on what you got, if you want to have a nice array for your collectionview, an array of tuples which will be filled by java datasource can be nice. A little sample of code to illustrate this :

var myJavaVar = JavaUtilLinkedHashMap()
var headerArray : [(varName : String, param : Int, varId : jlong)] = []


myJavaVar = myStaticMethodToGetMyVar

    //  get var array
    let keySetJava = myJavaVar.keySet().toArray()
    for jCounter in 0..<Int(myJavaVar.size()){
        // id for index
        let key : Int = keySetJava.objectAtIndex(UInt(jCounter)) as! Int
        let varId = jlong.init(key)
        let varName = myMethodToGetName(varId)
        let myParam : Int = myJavaVar.getWithId(keySetJava.objectAtIndex(UInt(jCounter))) as! Int
        // append data to the array
        headerArray.append((varName: categoryName, param : myParam,duration: duration, varId: varId))
    }

You can then get your data like this (in your collectionview method):

 let time = headerArray[indexPath.section].param
Unscathed answered 2/2, 2016 at 12:56 Comment(6)
But what prevents you to define a struct and use it in the array, instead of using the tuple? And why is a tuple better than a struct? It seems to me that the tuple just makes the code more difficult to read (which is subjective, I know).Cystectomy
Using a tuple was already a pain in the ass and you want to use a struct for this? This is just for the header cell, i let you imagine what it's like when you have to fill the normal cell array. How can have a named parameter makes the code more difficult to read?Unscathed
You can just define a struct named HeaderData (for example) with members varName, param and varId. The you have: var headerArray: [HeaderData] = []Cystectomy
yeah I agree it doesn't answer his question of WHY a tuple is necessarily better than a struct. Is it a matter of pure syntactic sugar?Leland
@Leland a tuple is a type you use as a return from a function, a struct serves another purpose entierely, pretty sure you can find some info on that in the swift documentation. This question and answer is two years old so...Unscathed
@thibautnoah You can use tuples for more than just a return from a function. Also, you can obviously return structs from a function. Arguably, the struct will be better defined and thought out because it required the developer to declare it. So, the question still stands, why would you use a tuple? Because you're too lazy to declare it?Leland

© 2022 - 2024 — McMap. All rights reserved.