When coding, we typically write code that tells the app to perform a series of steps to achieve a particular goal. When we want to perform this series of steps again somewhere in our code, we can’t help but introduce some form of repetition. Repetition of code by itself isn’t really harmful to the app, but it does for readability, especially when you’re working with other people who read your code regularly.
A way to lessen code repetition is to group your code into functions. A function
is basically a block of code that performs a specific task. You give a function a name (that describes the work it does), and this name can be used to “call” the function to perform all the work you’ve coded it to.
Defining a Function
/// A function that accepts two Int numbers /// adds them, then returns the sum func add(x: Int, y: Int) -> Int { return x + y }
The func
keyword
Functions are defined by using the func
keyword, followed by the name that describes the work it does. From the code snippet above, the function’s name is add
, because its task is to add two numbers and return the sum.
Function Parameters
A function can accept a number of parameters enclosed by parentheses. From the code snippet above, the add
function accepts two Int
parameters named x
and y
. These two Int
parameters are then added inside the body of the function to calculate the sum and return the value.
When declaring parameters, you need to specify the name and the type of each parameter. The name of a function parameter is also called an argument label
. From the code snippet above, the parameters x
and y
are the argument labels, while Int
is the type of both parameters. You can use Swift primitive types such as Int
or String
, or it can be instances of custom types you’ve written such as a class
, struct
, enum
, or protocol
. You can also pass functions as parameters but it’s best left to explore after you learn more about closures.
When you want to declare a function that accepts no parameter, you can simply do so by not specifying any parameter argument labels inside the parentheses.
/// A function that accepts no parameter func greetHello() { print("Hello!" } /// A function that accepts a single parameter func sayHello(name: String) { print("Hello \(name)!") } /// A function that accepts more than one parameters func sayHello(personA: String, personB: String) { print("Hello \(personA) and \(personB)!" }
Argument Labels
In Swift, you can specify the name of the parameter, and it may or may not be the same as the local variable that’ll hold the parameter value.
For instance, when we take the sayHello(personA:personB)
function above as an example, we can rewrite it with better readability by setting a custom argument label for each parameter.
/// Let's rewrite this function for better readability: func sayHello(personA: String, personB: String) { print("Hello \(personA) and \(personB)!") } /// by using argument labels, we can rewrite it as: func sayHello(to personA: String, and personB: String) { print("Hello \(personA) and \(personB)!") }
In the rewritten example, calling the sayHello
function would be more natural as its become closer to how we say it in the English language:
/// from calling the one without custom argument labels sayHello(personA: "Alice", personB: "Bob") // prints "Hello Alice and Bob!" /// to calling the one with custom argument labels sayHello(to: "Alice", and: "Bob") // prints "Hello Alice and Bob!"
Under the hood, both sayHello
functions work the same. In both cases, the function accepts two String
parameters and store them into personA
and personB
variables as locally-scoped properties.
Setting custom argument labels helps with readability, so make sure to use this amazing Swift language feature.
When you don’t want the function to have an argument label upon call you can do so by using the underscore _
symbol as the argument label.
func add(_ x: Int, _ y: Int) -> Int { return x + y } /// calling the add function above would no longer have argument labels: let sum = add(2, 3) print(sum) // prints 5
Return Type
Every function in Swift has a return type. You can specify the return type of the function by using the return arrow ->
operator.
// A function that returns an `Int` number func add(x: Int, y: Int) -> Int { ... } // A function that returns a `String` func sayHello(name: String) -> String { ... } // When you don't specify a return type, Swift will implicitly // identify it to return a special value of type Void. func print(_ s: String) { ... }
When you don’t specify a return type, Swift will treat the function to return a value of Void
type, which is simply an empty tuple ()
.
Both of these examples are the same:
func print(_ s: String) { ... } func print(_ s: String) -> Void { ... }
Function Signature and Body
The entire function declaration from the func
keyword, the name of the function, the parameters it accepts, and its return type is what’s called a function signature
; while the code block inside the curly braces { ... }
is what’s called the body
of the function.
// This is the function signature: func sayHello(name: String) -> String // while this is the function body: { return "Hello \(name)!" }
The signature
describes what a function is:
- what its name is
- what parameters it accepts
- what its return type would be
While the body
describes what work is done in sequential order of the code within it.
Calling a Function
As you may have noticed on previous examples above, to call a function, we can simply write its name and provide all parameters that it needs.
/// For example: func add(x: Int, y: Int) -> Int { return x + y } /// we can "call" the add function by: let sum = add(x: 2, y: 3) print(sum) // prints 5
Hope you get to learn the basic concepts of the use of functions.
Up next we’ll discuss closures, and functions that accept functions as parameter called higher-order functions.
That’s all for now, cheers!