How different are tuples in swift from structures? (1)
As I understand, both tuples and structures can be sent by value instead by reference in function calls, returns, right?
Also, I know that if have
var A : StructureX
var B : StructureX
I know that structure A and B have the same Type
, which is StructureX
. But...
let A : (Int, String)
let B : (Int, String)
Are A and B tuples the same Type
? (2)
What are the advantages about using Tuples instead of structures? (3)
Since tuples are structs there is no much point in making them immutable. The readonliness of a struct is a property of the whole variable. If a tuple variable is assignable, it can be changed to contain any value regardless of the readonliness of individual fields.
Value tuples are tuple types introduced in the . NET Framework 4.7 to provide the runtime implementation of tuples in C# and struct tuples in F#. They differ from the tuple classes, such as Tuple<T1>, Tuple<T1,T2>, etc., as follows: They are structures (value types) rather than classes (reference types).
You can create tuples from as many values as you want and from any number of different data types.
In Swift, a tuple is a group of different values. And, each value inside a tuple can be of different data types. Suppose we need to store information about the name and price of a product, we can create a tuple with a value to store name (string) and another value to store price (float)
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
typealias
in the code below)Differences Between Tuples and 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
}
I'm not sure the official terminology around tuples however, you declare them as if they were a special kind of type:
let A : (Int, String)
Maybe we could say that A is now a variable of type tuple? However, not all tuples are the same. If you declare variable of type tuple and try to assign it a tuple with parameters that differ in count, sequence, or type you'll get a compiler error. This will fail
let A : (Int, String) = ("Bob", 1234, 4.0)
Though this works fine:
let A : (Int, String) = (1234, "Bob")
Of course this strong type safety is also enforced with structs.
As far as the advantages, here are some thoughts on the differences I'm aware of.
Structures require that you define them before using them. Tuples, on the other hand, let you return an arbitrary list of values. How is this useful? I have an iPad app with a shopping cart view controller in it. There is a summary view in the cart view that displays a current status of what's in the cart at any given time--sometimes just normal items, but RMA items and items on re-order are also potentially in the cart. I have a method on my shopping cart class that returns a tuple containing cart count, RMA count, re-order count, and total count. I don't have to declare a structure to get back all four values. It's very convenient:
class Cart : NSManagedObject {
...
var totals : (cartCount:Int, rmaCount:Int, reorderedCount:Int, totalCount:Int) {
let cart = ... // Calculate cart count
let rma = ... // Calculate rma count
let reorder = ... // Calculate reorder count
let total = cart + rma + reorder // Add them all up
return (cart, rma, reorder, total)
}
}
In my cart view:
let cartValues = cart.totals
self.summaryView.cartCountLabel.text = "\(cartValues.cartCount)"
self.summaryView.rmaCountLabel.text = "\(cartValues.rmaCount)"
self.summaryView.reorderCountLabel.text = "\(cartValues.reorderedCount)"
self.summaryView.totalCountLabel.text = "\(cartValues.totalCount)"
There may be other reasons, but convenience is the most compelling one for me to prefer tuples in this scenario.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With