Is there any way to append an element/value to a tuple? - swift

Is there anyway to add a new element to a tuple?
var tuple = (v1: 1,v2: 2)
tuple.v3 = 3 // Error
"error: value of tuple type '(v1: Int, v2: Int)' has no member 'v3'"

No. Each tuple with a different number of elements or a different type of elements represents a different type in the Swift type system. Hence, once you create a tuple, you cannot append elements to it, because that would change the type of the tuple.
Some really basic examples of tuples and their types:
let tupleWithTwoInts = (1,2) //has type (Int,Int)
let tupleWithThreeInts = (1,2,3) //has type (Int,Int,Int)
let tupleWithTwoStrings = ("a","b") //has type (String,String)
let tupleWithIntAndString = (1,"a") //has type (Int,String)
let tupleWithStringAndInt = ("a",1) //has type (String,Int)
Even the order of the elements make a difference in the type of a tuple.
type(of: tupleWithIntAndString) == type(of: tupleWithStringAndInt) //false

If you just need to support some small number of operations, then you can write a function for it.
For example, extending a 2D vector into 3D:
func expand(_ v: (x: Int, y: Int), z: Int) -> (x: Int, y: Int, z: Int) {
return (x: v.x, y: v.y, z: z)
}

While there is no extensible way to convert your array to a tuple as stated above, if you arrived at this question because you are making reusable components, and you like the convenience that variadic declarations can provide, you can move your method body into one that takes an array and let your variadic declaration be an alternate wrapper for the same method.
This
func buttonModels(_ buttonModels: ButtonModel...) {
self.buttonModels = buttonModels
}
Becomes:
func buttonModels(_ buttonModels: ButtonModel...) {
self.buttonModels(buttonModels)
}
func buttonModels(_ buttonModels: [ButtonModel]) {
self.buttonModels = buttonModels
}

It seems to me that you are looking to use a dictionary, not a tuple. See the docs: Tuple
EDIT: As pointed out, tuples can indeed be mutable if you declare them as a var and can be used to hold editable data. My bad!

Related

Using Any instead of generics

Generics
Generic code enables you to write flexible, reusable functions and types that can work with any type, subject to requirements that you define. You can write code that avoids duplication and expresses its intent in a clear, abstracted manner.
Generics are one of the most powerful features of Swift, and much of the Swift standard library is built with generic code. In fact, you’ve been using generics throughout the Language Guide, even if you didn’t realize it. For example, Swift’s Array and Dictionary types are both generic collections. You can create an array that holds Int values, or an array that holds String values, or indeed an array for any other type that can be created in Swift. Similarly, you can create a dictionary to store values of any specified type, and there are no limitations on what that type can be.
The Problem That Generics Solve
Here’s a standard, nongeneric function called swapTwoInts(::), which swaps two Int values:
func swapTwoInts(_ a: inout Int, _ b: inout Int) {
let temporaryA = a
a = b
b = temporaryA
}
This function makes use of in-out parameters to swap the values of a
and b, as described in In-Out Parameters.
The swapTwoInts(::) function swaps the original value of b into a,
and the original value of a into b. You can call this function to swap
the values in two Int variables:
var someInt = 3
var anotherInt = 107
swapTwoInts(&someInt, &anotherInt)
print("someInt is now \(someInt), and anotherInt is now \(anotherInt)")
// Prints "someInt is now 107, and anotherInt is now 3" The
swapTwoInts(::) function is useful, but it can only be used with Int
values. If you want to swap two String values, or two Double values,
you have to write more functions, such as the swapTwoStrings(::) and
swapTwoDoubles(::) functions shown below:
func swapTwoStrings(_ a: inout String, _ b: inout String) {
let temporaryA = a
a = b
b = temporaryA
}
func swapTwoDoubles(_ a: inout Double, _ b: inout Double) {
let temporaryA = a
a = b
b = temporaryA
}
My question:
Instead of using generics function we could have just used Any type as the argument type right, that will simple as this
func swapTwoInts(_a:inout Any,_b:inout Int){
let temporaryA = a
a = b
b = temporaryA
}
So how to plays important role in swift?
Can I write code without generics like this
var num = 3
var numtwo = 5
print(num)
print(numtwo)
func swap(_ a: inout Any, _ b: inout Any){
let tempA=a
a=b
b=tempA
}
swap(a: &num, b: &numtwo)
In swift, you can assign value to a variable ONLY if the type of the variable is same with the value. So imagine you have this:
var a = 1
var b = 2
func swapTwoValues(_ a: inout Any, _ b: inout Any) {
let temporaryA = a
a = b
b = temporaryA
}
swapTwoValues(&a, &b) // <- Cannot pass immutable value as inout argument: implicit conversion from 'Int' to 'Any' requires a temporary
So compiler forces you to implicitly assign Any for the type of the variables. This is not what you want I think. So you have to tell the compiler that it doesn't matter the type of the arguments. The only thing matters is they both have same type to fulfill compilers need. So to achieve this, you can use generic or some kind of protocol.
func swapTwoValues<T>(_ a: inout T, _ b: inout T) {
let temporaryA = a
a = b
b = temporaryA
}
swapTwoValues(&a, &b) // Done
Tip: You can swap values with tuple in single line of code without using temporaryVar like this: (Even without function and generic and etc.)
(a, b) = (b, a)

Value-binding pattern with Swift structs

As the Programming Swift book describes, tuples can be destructured either in the assignment or by value-binding in a switch
let point = (3, 2)
switch point {
case let (x, y):
print("The point is at (\(x), \(y)).")
}
let (a, b) = point
print("The point is at (\(a), \(b)).")
I can't find any mention of how to do the equivalent for structs. For example:
struct S {
let a, b: Int
}
let s = S(a: 1, b: 2)
// This doesn't work:
// let (sa, sb): s
//
// Outputs: error: expression type 'S' is ambiguous without more context
// let (sa, sb) = s
// ^
This doesn't exist as such in the language.
One option is a helper computed property:
struct S {
let i: Int
let b: Bool
}
extension S {
var destructured: (Int, Bool) {
return (self.i, self.b)
}
}
let s = S(i: 10, b: false)
let (i, b) = s.destructured
Of course, you have to manually keep that in sync. Possibly Sourcery could assist with that.
Structs cannot be destructured in Swift.
Your tuple, point = (3, 2), is of type (Int, Int), which is part of why you are able to destructure it.
The type of your struct, S, is just S. Its variables, a and b, are not included in its type in the same literal way as they are for a tuple. A struct is simply a completely different kind of object, and this behavior does not exist for it.

Operators as callback functions in Swift

In Swift, operators are declared as functions. Does it mean they can also be used as callback functions? If so, how? If not, why?
Idea is, depending on the values of two different numbers, apply different operators to them.
In Swift functions are first class types, you can pass them as arguments to other functions expecting them.
A callback is nothing more than a parameter of another function.
Putting this all together means that yes, you can use an operator as a callback, as long as its type is compatible.
For example you can do:
[1, 2, 3, 4].reduce(0, combine: +)
// => 10
That is possible because + has type (Int, Int) -> Int, which matches the expected type for the combine: parameter of reduce when called on an array of Int.
Another example:
func foo(a: Int, f: (Int, Int) -> Int) -> Int {
return { a, f in
return f(a, 42)
}
}
foo(1, -)
// => 41

Swift Tuples - Different from struct and from each other?

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)
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
}
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.

Swift functions accepting tuples

Is it possible to pass in a tuple into a function as long as their types match up?
When I try it, I get a missing argument in parameter error:
var myTuple = ("Text",10,"More Text")
func myFunction(a:String, b:Int, c:String) {
// etc...
}
myFunction(myTuple)
It was possible, although was deprecated in Swift 2.2:
In Swift 2.1 and earlier it was possible to use a carefully crafted tuple to fill the parameters of a function. So, if you had a function that took two parameters, you could call it with a two-element tuple as long as the tuple had the correct types and element names.
...
This syntax — affectionately called “tuple splat syntax” — is the antithesis of idiomatic Swift’s self-documenting, readable style, and so it’s deprecated in Swift 2.2.
https://swift.org/blog/swift-2-2-new-features/
I came here wanting to know how to pass a tuple as a function parameter. The answers here focus on a different case. I'm not entirely clear what the OP was after.
In any case, here is how to pass a tuple as a parameter. And, for good measure, how to do it variadically.
func acceptTuple(tuple : (Int, String)) {
print("The Int is: \(tuple.0)")
print("The String is '\(tuple.1)'")
}
acceptTuple((45, "zebras"))
// Outputs:
// The Int is: 45
// The String is 'zebras'
func acceptTuples(tuples : (Int, String) ...) {
var index = 0
// note: you can't use the (index, tuple) pattern in the for loop,
// the compiler thinks you're trying to unpack the tuple, hence
/// use of a manual index
for tuple in tuples {
print("[\(index)] - Int is: \(tuple.0)")
print("[\(index)] - String is '\(tuple.1)'")
index++
}
}
acceptTuples((45, "zebras"), (17, "armadillos"), (12, "caterpillars"))
//Outputs
//[0] - Int is: 45
//[0] - String is 'zebras'
//[1] - Int is: 17
//[1] - String is 'armadillos'
//[2] - Int is: 12
//[2] - String is 'caterpillars'
Passing tuples in can be a quick and convenient approach, saving you from having to create wrappers etc. For example, I have a use case where I am passing a set of tokens and parameters to create a game level. Tuples makes this nice and compact:
// function signature
class func makeLevel(target: String, tokens: (TokenType, String)...) -> GameLevel
// The function is in the class Level. TokenType here is an Enum.
// example use:
let level = Level("Zoo Station", tokens:
(.Label, "Zebra"),
(.Bat, "LeftShape"),
(.RayTube, "HighPowered"),
(.Bat, "RightShape"),
(.GravityWell, "4"),
(.Accelerator, "Alpha"))
Yes, it's possible under these conditions:
the tuple must be immutable
the number of values in the tuple, their type, and their order must match the parameters expected by the function
named parameters must match external names in the function signature
non-named parameters must match parameters without external name in the function signature
So, your code is ok, the only thing you have to do is turning the tuple into an immutable one (i.e. using let and not var):
let myTuple = ("Text", 10, "More Text")
func myFunction(a:String, b:Int, c:String) {
// etc...
}
myFunction(myTuple)
One more example with external names:
let myTuple = ("Text", paramB: 10, paramC: "More Text")
func myFunction(a:String, paramB b:Int, paramC c:String) {
// etc...
}
myFunction(myTuple)
In your tuple, it appears as though you must name them and then refer to them as such:
so your code should be
var myTuple = (val1: "Text", val2: 10, val3: "More Text")
func myFunction(a:String, b:Int, c:String) {
// etc...
}
myFunction(myTuple.val1, myTuple.val2, myTuple.val3)
The tuple has named values (val1, val2, val3) which you set and then reference, when you pass in myTuple, to the function myFunction(), it appears as though you are just filling 1 of the 3 available arguements - and with the wrong type to boot! This is the equivalent of storing the types in a tuple, then taking them out for a function call. However, if you want a function to actually take a tuple as a parameter, see below:
var myTuple = (val1: "Text", val2: 10, val3: "More Text")
func tupleFunc(a:(String, Int, String)) {
}
tupleFunc(myTuple)
Yes, but that's the wrong structure: you're passing three variables called a, b, and c rather than a tuple with those components.
You need parentheses around the whole thing:
var myTuple = ("Text", 10, "More Text")
func myFunction(a:(x: String, y: Int, z: String)) {
println(a)
}
myFunction(myTuple)
You can use the following feature: Swift allows you to pass a function (f1) with any number of parameters (but without inout parameters) as a parameter of type (TIn) -> TOut to another function. In this case, TIn will represent a tuple from the parameters of the function f1:
precedencegroup ApplyArgumentPrecedence {
higherThan: BitwiseShiftPrecedence
}
infix operator <- :ApplyArgumentPrecedence
func <-<TIn, TOut>(f: ((TIn) -> TOut), arg: TIn) -> TOut {
return f(arg)
}
func sum(_ a: Int, _ b: Int) -> Int {
return a + b
}
print(sum <- (40, 2))
In swift 3.0, we should not able to pass the tuple directly to the function.If we did so, it shows the error message as "This type has been removed in swift 3.0"
func sum(x: Int, y: Int) -> Int
return x+y }
let params = (x: 1, y: 1)
let x = params.0
let y = params.1
sum(x: x, y: y)
Hope it helps you!!
The best option for now seems to be to just save it to a compound variable or use the build in dot syntax
let (val1, val2) = (1, 2)
func f(first: Int, second: Int) { }
f(first: val1, second: val2)
let vals = (1, 2)
f(first: vals.0, second: vals.1)
That feature called implicit tuple splat was removed in swift 3.
You can find more detailed explanation on the removal proposal here
Some suggestions to keep using tuple as an argument is by doing so:
func f1(_ a : (Int, Int)) { ... }
let x = (1, 2)
f1(x)
func f2<T>(_ a : T) -> T { ... }
let x = (1, 2)
f2(x)