Tuple vs Struct in Swift
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.
Swift Tuples - Different from struct and from each other?
I find it's easiest to conceptualize Swift Tuples as "Anonymous Structs" with a few critical differences. They behave similarly, but a struct has a formal definition and allows more control over mutability, while tuples allow for pattern matching.
Similarities Between Tuples and Structs
- Both may have any number of members of any type, including closures
- Both can be constructed inline (see
typealias
in the code below) - Both prevent mutation of any members if declared as constants
- If a tuple has labeled members, both structs and tuples allow member access by label
Differences Between Tuples and Structs
- Structs require a definition before use
- Structs do not allow pattern matching against their members
- Structs allow mutability of members declared as variables if the instance is a variable
- Tuples do not allow mutating functions or functions that refer to any of its members
- Tuples may not implement Protocols
- If a tuple has anonymous members, its members can be accessed by index, unlike structs
Some code for a playground illustrating these differences and similarities
// All commented code causes a compilation error. Uncomment to view error messages.
struct StructureX {
let a: Int = 0
var b: String = "string"
}
//
// Struct member variability
//
var structureA: StructureX = StructureX()
let structureB: StructureX = StructureX()
//structureA.a = 2 // declared as a constant, instance is variable
structureA.b = "allowed" // declared as a variable, instance is variable
//structureB.a = 2 // declared as constant, instance is constant
//structureB.b = "not allowed" // declared as constant, instance is constant
structureA = structureB // these are the same type
structureA
//
// A tuple can't be used as a literal to construct a struct.
//
//let StructureC: StructureX = (a: 17, b: "nope")
//
// Typealias a labeled tuple and it can be constructed similarly to a struct
//
typealias StructureT = (a: Int, b: String)
var structureD: StructureT = StructureT(a: 0, b: "asdf")
structureD
//structureD = structureA // but they are distinct types
let emptyTuple: () = () // philosophically, isn't this the definition of Void?
print(emptyTuple) // prints as ()
let single: (Int) = (23)
//let namedSingle: (a: Int) = (a: 42)
//
// Tuple Labeled Member Access
//
var labeledTupleA: (a: Int, b: String) = (a: 0, b: "string")
labeledTupleA.0 = 5
labeledTupleA.a
labeledTupleA
var check: (a: Int, b: String)
check = labeledTupleA // same type
check
//
// Tuples can have functions/closures
//
let labeledTupleB: (Int, String, fun: () -> Void) = (0, "string", { () -> Void in
print("hi")
})
labeledTupleB.1
labeledTupleB.fun()
//labeledTupleB.0 = 10 // this tuple is a constant, so all of its members are constant
//
// Tuples with members of the same type, but differet labels are not of the same type
//
var labeledTupleC: (c: Int, d: String) = (c: -1, d: "fail")
//labeledTupleC = labeledTupleA
//labeledTupleC = labeledTupleB
//
// Tuples with anonymous members matching the type pattern of a labeled member tuple are of equivalent type
//
var unlabeledTuple: (Int, String) = (0, "good")
unlabeledTuple = labeledTupleA
unlabeledTuple = labeledTupleC
//
// Tuples with closures may not refer to sibling members
//
var labeledTupleD: (de: Int, df: (Int) -> Void) = (de: 0, df: { (num: Int) -> Void in
//de += num
//self.de += num
print(num)
})
labeledTupleD.de
labeledTupleD.df(1)
//
// Tuples allow pattern matching, Structs do not
//
//switch structureA {
//case (let i, let s):
// print(i, s)
//default:
// break
//}
switch labeledTupleD {
case (_, let closure):
closure(123)
default:
break
}
Tuple vs. Object in Swift
As vadian notes, Apple's advice is that tuples only be used for temporary values. this plays out. If you need to do almost anything non-trivial with a data structure, including store it in a property, you probably do not want a tuple. They're very limited.
I'd avoid the term "object" in this discussion. That's a vague, descriptive term that doesn't cleanly map to any particular data structure. The correct way to think of a tuple is as being in contrast to a struct. In principle, a tuple is just an anonymous struct, but in Swift a tuple is dramatically less flexible than a struct. Most significantly, you cannot add extensions to a tuple, and adding extensions is a core part of Swift programming.
Basically, about the time you're thinking that you need to label the fields of the tuple, you probably should be using a struct instead. Types as simple as "a point" are modeled as structs, not tuples.
So when would you ever use a tuple? Consider the follow (non-existent) method on Collection:
extension Collection {
func headTail() -> (Element?, SubSequence) {
return (first, dropFirst())
}
}
This is a good use of a tuple. It would be unhelpful to invent a special struct just to return this value, and callers will almost always want to destructure this anyway like:
let (head, tail) = list.headTail()
This is one thing that tuples can do that structs cannot (at least today; there is ongoing discussion of adding struct destructuring and pattern matching to Swift).
What's the difference between struct and typealias in swift?
You are comparing a struct
with the typealias of a tuple
.
A struct is much more powerful than a tuple, here's some advantages only a struct offers
- a struct can conform to a protocol, a tuple can't
- a struct can have methods, a tuple can't
- a struct can have computed properties, a tuple can't
- a struct can have initializers, a tuple can't
Considerations
I suggest you to use a struct for your model. It's a better fit for a model value.
Someday you'll need to add a computed property (like birthYear
) to your type and you don't want to be constrained by the limitations of simple tuple.
Why use a tuple rather than an array or dictionary in Swift?
A tuple can contain elements of different types. So for example you could declare a tuple containing a String and an Int, while all elements of an array have to be the same type, unless you use AnyObject and type casting.
Single-value-tuple as last member of struct in swift
MusicPlayer is no longer exported as above. As of Xcode 6.3b1
typedef struct MusicEventUserData
{
UInt32 length;
UInt8 data[1];
} MusicEventUserData;
This is much closer to the C declaration. It still does not completely explain how to deal with the API in swift but that is another question.
When should tuples be used instead of objects and vice versa?
According to the book on Swift,
Tuples are useful for temporary groups of related values. They are not suited to the creation of complex data structures.
They define "temporary" through the scope of the data: if a piece of data never leaves the scope of a single method, or a group of methods of the same object, it can be considered temporary, even though it might very well persist through the lifetime of an application.
If your data structure is useful outside a temporary scope - for example, because it needs to be returned from a public method of your class, model it as a class or structure, rather than as a tuple.
Another important consideration is associating behavior with your data: if your object needs to have methods, use classes for them. Use tuples only for data devoid of behavior.
Related Topics
In Swift, Does Resetting the Property Inside Didset Trigger Another Didset
Can You Give Uistackview Borders
How to Open the Parent App on iPhone from My Watchkit App
What Is the "@Exported" Attribute in Swift
How to Bind a Variable to Multiple Alternatives in a Switch Statement
Not Condition in 'If Case' Statement
How to Handle Multiple Network Call in Alamofire
Creating a Custom Scngeometry Polygon Plane with Scngeometryprimitivetype Polygon Crash/Error
Read a File in a MACos Command Line Tool Project
Clearing Uiwebview's Cache in Swift
Swift Anyobject Is Not Convertible to String/Int
Local Notification While App Not Running
Does Kotlin Has Extension Class to Interface Like Swift
Include an Extension for a Class Only If iOS11 Is Available
Cannot Use Mutating Member on Immutable Value of Type
How to Succinctly Get the First 5 Characters of a String in Swift
Swift 4 Codable - API Provides Sometimes an Int Sometimes a String