5
Functions

WHAT YOU WILL LEARN IN THIS CHAPTER:            

  • How to define and call a function
  • How to define input parameters
  • How to return a value or multiple values from a function
  • How to define external parameter names
  • How to define default parameter values
  • How to define variadic parameters
  • How to define constant and variable parameters
  • How to define in-out parameters
  • How to define and call function type variables
  • How to return a function type from a function
  • How to define nested functions

A function is a group of statements that perform a specific set of tasks. For example, a particular function may calculate the bonus of an employee based on a few parameters, such as his or her performance rating, number of years in the company, and so on. A function may also return a value, such as the amount of bonus to which an employee is entitled. In Swift, a function has a name, and it may also accept parameters and optionally return a value (or a set of values). Functions in Swift work similarly to traditional C functions, and they also support features such as external parameter names, which enables them to mirror the verbosity of Objective-C methods.

DEFINING AND CALLING A FUNCTION

In Swift, a function is defined using the func keyword, like this:

func doSomething() {
   println("doSomething")
}

The preceding code snippet defines a function called doSomething. It does not take in any inputs (known as parameters) and does not return a value (technically it does return a Void value).

To call the function, simply call its name followed by a pair of empty parentheses:

doSomething()

Input Parameters

A function can also optionally define one or more named typed inputs. The following function takes in one single typed input parameter:

func doSomething(num: Int) {    
    println(num)
}

The num parameter is used internally within the function, and its data type is Int. To call this function, call its name and pass in an integer value (known as an argument), like this:

doSomething(5)
//---or---
var num = 5
doSomething(num)

The following function takes in two input parameters, both of type Int:

func doSomething(num1: Int, num2: Int) {
    println(num1, num2)
}

To call this function, pass it two integer values as the argument:

doSomething(5, 6)

Returning a Value

Functions are not required to return a value. However, if you want the function to return a value, use the -> operator after the function declaration. The following function returns an integer value:

func doSomething(num1: Int, num2: Int, num3: Int) -> Int {
    return num1 + num2 + num3
}

You use the return keyword to return a value from a function and then exit it. When the function returns a value, you can assign it to a variable or constant, like this:

//---value returned from the function is assigned to a variable---
var sum = doSomething(5,6,7)

Return values from a function can also be ignored:

//---return value from a function is ignored---
doSomething(5,6,7)

Returning Multiple Values

Functions are not limited to returning a single value. In some cases, it is important for functions to return multiple values. In Swift, you can use a tuple type in a function to return multiple values. The following example shows a function that takes in a string containing numbers, examines each character in the string, and counts the number of odd and even numbers contained in it:

func countNumbers(string: String) -> (odd:Int, even:Int) {
   var odd = 0, even = 0
   for char in string {
      let digit = String(char).toInt()
      if (digit != nil) {
          (digit!) % 2 == 0 ? even++ : odd++
      }
   }
   return (odd, even)
}

The (odd:Int, even:Int) return type specifies the members of the tuple that would be returned by the function—odd (of type Int) and even (of type Int).

To use this function, pass it a string and assign the result to a variable or constant, like this:

var result = countNumbers("123456789")

The return result is stored as a tuple containing two integer members, named odd and even:

println("Odd: (result.odd)")         //---5---
println("Even: (result.even)")       //---4---

Function Parameter Names

So far in the previous discussion of functions with parameters, each parameter has a name. Take the example of this function shown previously:

func doSomething(num1: Int, num2: Int) {
    println(num1, num2)
}

In this example, num1 and num2 are the two parameters names for the function and they can only be used internally within the function. These are called local parameter names.

When calling this function, these two parameters names are not used at all:

doSomething(5, 6)

In more complex functions with multiple parameters, the use of each parameter is sometimes not obvious. Therefore, it would be useful to be able to name the parameter(s) when passing arguments to a function. In Swift, you can assign an external parameter name to individual parameters in a function. Consider the following example:

func doSomething(num1: Int, secondNum num2: Int) {

}

In this example, the second parameter is prefixed with an external parameter name secondNum. To call the function, you now need to specify the external parameter name, like this:

doSomething(5, secondNum:6)

You can also specify an external parameter name for the first parameter, such as the following:

func doSomething(firstNum num1: Int, secondNum num2: Int) {

}

In this case, you need to specify external parameter names for both parameters:

doSomething(firstNum:5, secondNum:6)

Figure 5.1 shows the difference between external and local parameter names.

images

Figure 5.1

External parameter names are very useful for making function names descriptive. Consider the following examples of calling functions using external parameter names:

calculateDistance(point1, fromSecondPoint:point2)
printName(strName, withTitle:"Dr.")
joinString(str1, withString2:str2 andString3:str3 usingSeparator:",")

External Parameter Names Shorthand

Sometimes the local parameter name itself is descriptive enough to be used as an external parameter name. Consider the previous example:

func doSomething(num1: Int, num2: Int) {
    println(num1, num2)
}

Suppose you want to use num1 as the external parameter name for the first parameter and num2 for the second parameter. You could write it as follows:

func doSomething(num1 num1: Int, num2 num2: Int) {

}

Instead of repeating the parameter names twice, you could use the shorthand #, like this:

func doSomething(#num1: Int, #num2: Int) {

}

To call the function, you specify the external parameter names like this:

doSomething(num1:5, num2:6)

Default Parameter Values

You can assign a default value to a parameter so that it becomes optional when you are calling it. Consider the following function in which you have three parameters:

func joinName(firstName:String,
              lastName:String,
              joiner:String = " ") -> String {
    return "(firstName)(joiner)(lastName)"
}

The third parameter has a default value of a single space. When calling this function with three arguments, you need to specify the default parameter name, like this:

var fullName = joinName("Wei-Meng", "Lee", joiner:",")
println(fullName)  //---Wei-Meng,Lee---

You can omit the default parameter when calling the function and it will use the default value of the single space for the third argument:

fullName = joinName("Wei-Meng","Lee")
println(fullName)   //---Wei-Meng Lee---

You need to be careful when defining functions of the same name but with different input parameters. Consider the case where you have two functions both named joinName and the first one has a default parameter:

func joinName(firstName:String,
              lastName:String,
              joiner:String = " ") -> String {
    return "(firstName)(joiner)(lastName)"
}

func joinName(firstName:String,
              lastName:String) -> String {
    return "(firstName)(lastName)"
}

To call the first function, you need to specify the external parameter name for the default parameter, like this:

var fullName = joinName("Wei-Meng", "Lee", joiner:",")
println(fullName)  //---Wei-Meng,Lee---

If you now call joinName by passing only two arguments, it will result in a compilation error because the compiler is not able to resolve which function to call:

var fullName = joinName("Wei-Meng","Lee")

Variadic (Variable) Parameters

In some situations you may need to define a function that accepts a variable number of arguments. For example, suppose you want to define a function that calculates the average of a series of numbers passed in as arguments. In this case your function can be defined as follows:

func average(nums: Int...) -> Float {
   var sum: Float = 0
   for num in nums {
      sum += Float(num)
   }
   return sum/Float(nums.count)
}

The . . . (three periods) indicates that the parameter accepts a varying number of arguments, which in this case are of type Int. A parameter that accepts a variable number of values is known as a variadic parameter. You can call the function by passing it arguments of any length:

println(average(1,2,3))        //---2.0---
println(average(1,2,3,4))      //---2.5---
println(average(1,2,3,4,5,6))  //---3.4---

Constant and Variable Parameters

By default, all the parameters in a function are constants. In other words, your code within the function is not allowed to modify the parameter. The following illustrates this:

func doSomething(num: Int) {
    num++  //---this is illegal as num is a constant by default---
    println(num)
}

If you want to modify the value of a parameter, you can copy it out to another variable, like this:

func doSomething(num: Int) {
    var n = num
    n++
    println(n)
}

However, there is an easier way: Simply prefix the parameter name with the var keyword to make the parameter a variable:

func doSomething(var num: Int) {
    num++
    println(num)
}

Note that the parameter duplicates a copy of the argument that is passed in, as the following code snippet shows:

num = 8
doSomething(num)  //---prints out 9---
println(num)      //---prints out 8; original value of 8 is unchanged---

Any changes made to the variable that is passed to the function remain unchanged after the function has exited.

In-Out Parameters

The previous section showed that a variable passed into a function does not change its value after a function call has returned. This is because the function makes a copy of the variable and all changes are made to the copy.

However, sometimes you want a function to change the value of a variable after it has returned. A parameter that persists the changes made within the function is known as an in-out parameter. The following shows an example of an in-out parameter:

func fullName(inout name:String, withTitle title:String)  {
    name = title + " " + name;
}

In the preceding example, the name parameter is prefixed with the inout keyword. This keyword specifies that changes made to the name parameter will be persisted after the function has returned. To see how this works, consider the following code snippet:

var myName = "Wei-Meng Lee"
fullName(&myName, withTitle:"Mr.")
println(myName)  //---prints out "Mr. Wei-Meng Lee"---

As you can see, the original value of myName was “Wei-Meng Lee”. However, after the function has returned, its value has changed to “Mr. Wei-Meng Lee”.

Here are the things you need to know when calling a function with inout parameters:

  • You need to pass a variable to an inout parameter; constants are not allowed.
  • You need to prefix the & character before the variable that is passed into an inout parameter, to indicate that its value can be changed by the function.
  • In-out parameters cannot have default values.
  • In-out parameters cannot be marked with the var or let keyword.

FUNCTION TYPES

Every function has a specific function type. To understand this, consider the following two functions:

func sum(num1: Int, num2: Int) -> Int {
   return num1 + num2
}

func diff(num1: Int, num2: Int) -> Int {
   return abs(num1 - num2)
}

Both functions accept two parameters and return a value of type Int. The type of each function is hence (Int, Int) -> Int.

As another example, the following function has the type () -> (), which you can read as “a function that does not have any parameters and returns Void”:

func doSomething() {
   println("doSomething")
}

Defining a Function Type Variable

In Swift, you can define a variable or constant as a function type. For example, you could do the following:

var myFunction: (Int, Int) -> Int

The preceding statement basically defines a variable called myFunction of type “a function that takes in two Int parameters and returns an Int value.” Because myFunc has the same function type as the sum() function discussed earlier, you can then assign the sum() function to it:

myFunction = sum

You can shorten the preceding statements to:

var myFunction: (Int, Int) -> Int = sum

Calling a Function Type Variable

You can now call the sum() function using the function type variable myFunction, like this:

println(myFunction(3,4))  //---prints out 7---

The myFunction variable can be assigned another function that has the (Int, Int) -> Int function type:

myFunction = diff

This time, if you call the myFunction again, you will instead be calling the diff() function:

println(myFunction(3,4))  //---prints out 1---

The following table shows the definition of some functions and their corresponding function types.

FUNCTION DEFINITION FUNCTION TYPE (DESCRIPTION)

func average(nums: Int...)

-> Float {

}

(Int...) -> Float

The parameter is a variadic parameter; hence, you need to specify the three periods (...).

func joinName(firstName:String,

lastName:String,

joiner:String = " ")

-> String {

}

(String, String, String) -> String

You need to specify the type for the default parameter (third parameter).

func doSomething(num1: Int,

num2: Int) {

}

(Int, Int) -> ()

The function does not return a value; hence, you need the () in the function type.

func doSomething() {

}

() -> ()

The function does not have any parameter and does not return a value; hence, you need to specify the () for both parameter and return type.

Returning Function Type in a Function

A function type can be used as the return type of a function. Consider the following example:

func chooseFunction(choice:Int) -> (Int, Int)->Int {
   if choice == 0 {
      return sum
   } else {
      return diff
   }
}

The chooseFunction() function takes in an Int parameter and returns a function of type (Int, Int) -> Int. In this case, if choice is 0, then it returns the sum() function; otherwise it returns the diff() function.

To use the chooseFunction() function, call it and pass in a value and assign its return value to a variable or constant:

var functionToUse = chooseFunction(0)

The return value can now be called like a function:

println(functionToUse(2,6))       //---prints out 8---

functionToUse = chooseFunction(1)
println(functionToUse(2,6))       //---prints out 4---

NESTED FUNCTIONS

You can define functions within a function—this is known as nested functions. A nested function can only be called within the function in which it is defined.

The chooseFunction() function shown in the previous section can be rewritten using nested functions:

func chooseFunction(function:Int) -> (Int, Int)->Int {
   func sum(num1: Int, num2: Int) -> Int {
      return num1 + num2
   }

   func diff(num1: Int, num2: Int) -> Int {
      return abs(num1 - num2)
   }

   if function == 0 {
      return sum
   } else {
      return diff
   }
}

SUMMARY

In this chapter, you have seen how functions are defined and used. You have also seen the various types of parameters that you can define in your functions and how to call them. Functions play a pivotal role in Swift programming, as they are the cornerstone of object-oriented programming. Chapter 8 discusses how functions are used in classes.

EXERCISES

  1. Modify the following code snippet so that it can also return the number of digits divisible by 3:

        func countNumbers(string: String) -> (odd:Int, even:Int) {
            var odd = 0, even = 0
            for char in string {
                let digit = String(char).toInt()
                if (digit != nil) {
                    (digit!) % 2 == 0 ? even++ : odd++
                }
            }
            return (odd, even)
        }
  2. Declare a function so that you can call it like this:

            doSomething("abc", withSomething: "xyz")
  3. Write a function that takes in a variable number of Int parameters and returns the sum of all the arguments.

  4. Write a variadic function called cat() using default parameters that can be called in the following manner with the outputs shown:

            println(cat(joiner:":", nums: 1,2,3,4,5,6,7,8,9))
            // 1:2:3:4:5:6:7:8:9
    
            println(cat(nums: 1,2,3,4,5))
            // 1 2 3 4 5

arrow2 WHAT YOU LEARNED IN THIS CHAPTER

TOPIC KEY CONCEPTS
Defining a function Use the func keyword.
Returning multiple values from a function Use a tuple to return multiple values from a function.
External parameter names You can specify an external parameter name to a parameter in a function.
External parameter names shorthand To use the parameter name as an external parameter name, use the # character.
Default parameter values You can specify default values for a parameter. For default parameters, you need to specify the parameter name explicitly when calling the function. In addition, for a default parameter, there is no need to specify an external parameter name or use the # shorthand when defining the function, as the default parameter implicitly indicates a named argument.
Variadic parameters A parameter that accepts a variable number of values is known as a variadic parameter. Note that a variadic parameter must appear last in the parameter list. Also, if you have a function that accepts default parameter values, the variadic parameter must be last in the parameter list.
Constant parameters By default, all the parameters in a function are constants. To modify the values of parameters, prefix them with the var keyword.
In-out parameters A parameter that persists the changes made within the function is known as an in-out parameter.
Function types Every function has a specific function type—it specifies the parameters’ list and the return type.
Calling a function type variable You can call a function type variable just like a normal variable.
Returning a function type in a function You can return a function type from a function.
Nested functions You can embed functions within a function.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.129.62.161