Functions are blocks of code organized together to perform a specific task. A function is given a name that identifies what it does, and this name is used to âcallâ the function to perform its task when needed.
Defining and Calling Functions
Every function has a function name
, which describes the task that the function performs.
To use a function, you âcallâ that function with its name and pass it input values (known as arguments
) that match the types of the functionâs parameters.
A functionâs arguments must always be provided in the same order as the functionâs parameter list.
The figure below describes the syntax of functions in Swift:
Functions Without Parameters
Functions arenât required to define input parameters.
Functions With Multiple Parameters
Functions can have multiple input parameters, which are written within the functionâs parentheses, separated by commas.
Functions Without Return Values
Functions arenât required to define a return type.
Hereâs a version of the greet(person:)
function, which prints its own String
value rather than returning it:
Because it doesnât need to return a value,
the functionâs definition doesnât include the return arrow (->
)
or a return type.
Note
Strictly speaking, this version of the
greet(person:)
function does still return a value, even though no return value is defined. Functions without a defined return type return a special value of typeVoid
.
Functions with Multiple Return Values
You can use a tuple
type as the return type for a function to return multiple values as part of one compound return value.
The example below defines a function called minMax(array:)
, which finds the smallest and largest numbers in an array of Int
values:
The minMax(array:)
function returns a tuple containing two Int
values.
These values are labeled min
and max
so that they can be accessed by name when querying the functionâs return value.
Because the tupleâs member values are named as part of the functionâs return type, they can be accessed with dot syntax to retrieve the minimum and maximum found values:
Functions With an Implicit Return
If the entire body of the function is a single expression, the function implicitly returns that expression.
For example, both functions below have the same behavior:
Function Argument Labels and Parameter Names
Each function parameter has both an argument label and a parameter name. The argument label is used when calling the function; each argument is written in the function call with its argument label before it. The parameter name is used in the implementation of the function. By default, parameters use their parameter name as their argument label.
All parameters must have unique names. Although itâs possible for multiple parameters to have the same argument label, unique argument labels help make your code more readable.
Specifying Argument Labels
You write an argument label before the parameter name, separated by a space:
Hereâs a variation of the greet(person:)
function
that takes a personâs name and hometown
and returns a greeting:
The use of argument labels can allow a function to be called in an expressive, sentence-like manner, while still providing a function body thatâs readable and clear in intent.
Omitting Argument Labels
If you donât want an argument label for a parameter,
write an underscore (_
) instead of an explicit argument label for that parameter.
If a parameter has an argument label, the argument must be labeled when you call the function.
Default Parameter Values
You can define a default value for any parameter in a function by assigning a value to the parameter after that parameterâs type. If a default value is defined, you can omit that parameter when calling the function.
Place parameters that donât have default values at the beginning of a functionâs parameter list, before the parameters that have default values. Parameters that donât have default values are usually more important to the functionâs meaning --- writing them first makes it easier to recognize that the same function is being called, regardless of whether any default parameters are omitted.
Variadic Parameters
A variadic parameter accepts zero or more values of a specified type.
You use a variadic parameter to specify that the parameter can be passed
a varying number of input values when the function is called.
Write variadic parameters by inserting three period characters (...
)
after the parameterâs type name.
The values passed to a variadic parameter are made available within the functionâs body
as an array of the appropriate type.
For example, a variadic parameter with a name of numbers
and a type of Double...
is made available within the functionâs body as
a constant array called numbers
of type [Double]
.
The example below calculates the arithmetic mean (also known as the average) for a list of numbers of any length:
A function can have multiple variadic parameters. The first parameter that comes after a variadic parameter must have an argument label. The argument label makes it unambiguous which arguments are passed to the variadic parameter and which arguments are passed to the parameters that come after the variadic parameter.
In-Out Parameters
Function parameters are constants by default. Trying to change the value of a function parameter from within the body of that function results in a compile-time error. This means that you canât change the value of a parameter by mistake. If you want a function to modify a parameterâs value, and you want those changes to persist after the function call has ended, define that parameter as an in-out parameter instead.
You write an in-out parameter by placing the inout
keyword
right before a parameterâs type.
An in-out parameter has a value thatâs passed in to the function,
is modified by the function,
and is passed back out of the function to replace the original value.
For a detailed discussion of the behavior of in-out parameters
and associated compiler optimizations,
see doc:Declarations#In-Out-Parameters.
You can only pass a variable as the argument for an in-out parameter.
You canât pass a constant or a literal value as the argument,
because constants and literals canât be modified.
You place an ampersand (&
) directly before a variableâs name
when you pass it as an argument to an in-out parameter,
to indicate that it can be modified by the function.
Note: In-out parameters canât have default values, and variadic parameters canât be marked as
inout
.
Hereâs an example of a function called swapTwoInts(_:_:)
,
which has two in-out integer parameters called a
and b
:
The swapTwoInts(_:_:)
function simply swaps the value of b
into a
,
and the value of a
into b
.
The function performs this swap by storing the value of a
in
a temporary constant called temporaryA
, assigning the value of b
to a
,
and then assigning temporaryA
to b
.
You can call the swapTwoInts(_:_:)
function with two variables of type Int
to swap their values.
Note that the names of someInt
and anotherInt
are prefixed with an ampersand
when theyâre passed to the swapTwoInts(_:_:)
function:
The example above shows that
the original values of someInt
and anotherInt
are modified by the swapTwoInts(_:_:)
function,
even though they were originally defined outside of the function.
Note: In-out parameters arenât the same as returning a value from a function. The
swapTwoInts
example above doesnât define a return type or return a value, but it still modifies the values ofsomeInt
andanotherInt
. In-out parameters are an alternative way for a function to have an effect outside of the scope of its function body.
Function Types
Every function has a specific function type, made up of the parameter types and the return type of the function.
For example:
This example defines two simple mathematical functions
called addTwoInts
and multiplyTwoInts
.
These functions each take two Int
values,
and return an Int
value, which is the result of
performing an appropriate mathematical operation.
The type of both of these functions is (Int, Int) -> Int
.
This can be read as:
âA function that has two parameters, both of type Int
,
and that returns a value of type Int
.â
Hereâs another example, for a function with no parameters or return value:
The type of this function is () -> Void
,
or âa function that has no parameters, and returns Void
.â
Using Function Types
You use function types just like any other types in Swift. For example, you can define a constant or variable to be of a function type and assign an appropriate function to that variable:
This can be read as:
âDefine a variable called mathFunction
,
which has a type of âa function that takes two Int
values,
and returns an Int
value.â
Set this new variable to refer to the function called addTwoInts
.â
The addTwoInts(_:_:)
function has the same type as the mathFunction
variable,
and so this assignment is allowed by Swiftâs type-checker.
You can now call the assigned function with the name mathFunction
:
A different function with the same matching type can be assigned to the same variable, in the same way as for nonfunction types:
As with any other type, you can leave it to Swift to infer the function type when you assign a function to a constant or variable:
Function Types as Parameter Types
You can use a function type such as (Int, Int) -> Int
as a parameter type for another function.
This enables you to leave some aspects of a functionâs implementation
for the functionâs caller to provide when the function is called.
Hereâs an example to print the results of the math functions from above:
This example defines a function called printMathResult(_:_:_:)
, which has three parameters.
The first parameter is called mathFunction
, and is of type (Int, Int) -> Int
.
You can pass any function of that type as the argument for this first parameter.
The second and third parameters are called a
and b
, and are both of type Int
.
These are used as the two input values for the provided math function.
When printMathResult(_:_:_:)
is called,
itâs passed the addTwoInts(_:_:)
function, and the integer values 3
and 5
.
It calls the provided function with the values 3
and 5
, and prints the result of 8
.
The role of printMathResult(_:_:_:)
is to print the result of
a call to a math function of an appropriate type.
It doesnât matter what that functionâs implementation actually does ---
it matters only that the function is of the correct type.
This enables printMathResult(_:_:_:)
to hand off some of its functionality
to the caller of the function in a type-safe way.
Function Types as Return Types
You can use a function type as the return type of another function.
You do this by writing a complete function type
immediately after the return arrow (->
) of the returning function.
The next example defines two simple functions called stepForward(_:)
and stepBackward(_:)
.
The stepForward(_:)
function returns a value one more than its input value,
and the stepBackward(_:)
function returns a value one less than its input value.
Both functions have a type of (Int) -> Int
:
Hereâs a function called chooseStepFunction(backward:)
,
whose return type is (Int) -> Int
.
The chooseStepFunction(backward:)
function returns the stepForward(_:)
function
or the stepBackward(_:)
function based on a Boolean parameter called backward
:
You can now use chooseStepFunction(backward:)
to obtain a function
that will step in one direction or the other:
The example above determines whether a positive or negative step is needed
to move a variable called currentValue
progressively closer to zero.
currentValue
has an initial value of 3
,
which means that currentValue > 0
returns true
,
causing chooseStepFunction(backward:)
to return the stepBackward(_:)
function.
A reference to the returned function is stored in a constant called moveNearerToZero
.
Now that moveNearerToZero
refers to the correct function,
it can be used to count to zero:
Nested Functions
All of the functions you have encountered so far in this chapter have been examples of global functions, which are defined at a global scope. You can also define functions inside the bodies of other functions, known as nested functions.
Nested functions are hidden from the outside world by default, but can still be called and used by their enclosing function. An enclosing function can also return one of its nested functions to allow the nested function to be used in another scope.
You can rewrite the chooseStepFunction(backward:)
example above
to use and return nested functions: