Life has two rules: 1.Never quit. 2. Always remember rule #1
Agenda
- Reuse code with functions
- Return value from functions
- Return multiple values from functions
- Customize parameter labels
Reuse code with functions
Functions are used so that the block of code can be reused multiple times.
Syntax:
func func_name() {
Statements
}
The function is called as follows func_name()
. You can add parameters inside the braces. Look at the following example.
func printTimesTables(number: Int, end: Int) {
for i in 1...end {
print("\(i) x \(number) is \(i * number)")
}
}
//Calling the function with parameters.
printTimesTables(number: 5, end: 20)
Return value from functions
You can return a value from within a function. That value can be assigned to a variable or constant out side the function. Here is an example.
func rollDice() -> Int {
return Int.random(in: 1...6)
}
let result = rollDice()
print(result)
Notice how “-> Int” is added after the function name. That indicates what type of data is returned by the function. Because of this you code won’t build if you are not returning any value.
Additionally, there is another piece of advantage in swift when returning a value. So, you have indicated that your function will return a value of type Int. If your function has only one line of code, swift will return the value of that statement. For example, in our previous illustration we have use return Int.random(in: 1...6)
. Since that is the only statement inside the function we can ignore the keyword return.
func rollDice() -> Int {
Int.random(in: 1...6)
}
let result = rollDice()
print(result)
Return multiple values from functions
If you want to return two or more values from a function, you could use an array. For example.
func getUser() -> [String] {
["Taylor", "Swift"]
}
let user = getUser()
print("Name: \(user[0]) \(user[1])")
However, this solution may not work if the values of the array are rearranged. This can create problems. Alternatively, you can use dictionaries.
func getUser() -> [String: String] {
[
"firstName": "Taylor",
"lastName": "Swift"
]
}
let user = getUser()
print("Name: \(user["firstName", default: "Anonymous"]) \(user["lastName", default: "Anonymous"])")
This leads to another problem. See even though you have clearly mentioned firstName and lastName, because you are using dictionaries you need to allocated default values for each when printing them. Even though it works, we can have simpler solution. Swift offers tuples as solution.
func getUser() -> (firstName: String, lastName: String) {
(firstName: "Taylor", lastName: "Swift")
}
let user = getUser()
print("Name: \(user.firstName) \(user.lastName)")
Tuples are a collection data type which can take multiple pieces of data, have a fixed size and can have a variety of data types.
Optimization #1
Since tuples have a fixed size, when you are returning values by using tuple, you have to use their names again after declaration. Swift will assign the values in order.
func getUser() -> (firstName: String, lastName: String) {
("Taylor", "Swift")
}
Optimization #2
Sometimes you will find you are given tuples where the elements don’t have names. In this case, you can access the tuple’s elements using numerical indices starting from 0.
func getUser() -> (String, String) {
("Taylor", "Swift")
}
let user = getUser()
print("Name: \(user.0) \(user.1)")
Optimization #3
If a function returns a tuple you can actually pull the tuple apart into individual values if you want to.
func getUser() -> (firstName: String, lastName: String) {
(firstName: "Taylor", lastName: "Swift")
}
let user = getUser()
let firstName = user.firstName
let lastName = user.lastName
print("Name: \(firstName) \(lastName)")
You can also eliminate one additional step when using tuples. Instead of assigning the return values to a constant user and then calling individual parts, you can use a tuple instead.
let (first, last) = getUser()
If you don’t need a part of the tuple from the function, you can say swift to ignore it by using _ in its position. Say for example, you don’t need to know the value of lastName. You can do as follows.
let (first, _) = getUser()
Customize parameter labels
The name of the parameter inside a function is highly useful when you are calling a funciton.
func hireEmployee(name: String) { }
func hireEmployee(title: String) { }
func hireEmployee(location: String) { }
In the above code, all there functions have the same name. But depending on the name of the parameter, swift calls the correct method.
But using the parameter name when calling it can be annoying and difficult to read sometimes. Take this for example.
func isUppercase(string: String) -> Bool {
string == string.uppercased()
}
let string = "HELLO, WORLD"
let result = isUppercase(string: string)
See the last line where you say string:string. This adds confusion as well. To solve this problem we use _ inside the function to ignore the external parameter label.
func isUppercase(_ string: String) -> Bool {
string == string.uppercased()
}
let string = "HELLO, WORLD"
let result = isUppercase(string)
This looks much better to read.
The second problem which was discussed on the tutorial is using the correct names that makes sense. Let us look at the example.
func printTimesTables(number: Int) {
for i in 1...12 {
print("\(i) x \(number) is \(i * number)")
}
}
printTimesTables(number: 5)
This is quite correct, however, if the parameter label is a little different it makes whole lot of difference when calling the function. The above can be converted into this.
func printTimesTables(for: Int) {
for i in 1...12 {
print("\(i) x \(for) is \(i * for)")
}
}
printTimesTables(for: 5)
It adds more clarity while reading and calling the function. But “for” is a keyword and cannot be used as a function parameter label. To solve this, we can add a second name for internal use.
func printTimesTables(for number: Int) {
for i in 1...12 {
print("\(i) x \(number) is \(i * number)")
}
}
printTimesTables(for: 5)
The internal name is number. The external name is for. The external name is used to call the function.
That is all for today’s learning. See you tomorrow.