Programming in Swift: Fundamentals

Oct 19 2021 · Swift 5.5, iOS 15, Xcode 13

Part 5: Functions & Named Types

36. Functions & Return

Episode complete

Play next episode

Next
About this episode

Leave a rating/review

See forum comments
Cinema mode Mark complete Download course materials
Previous episode: 35. Introduction to Functions Next episode: 37. Challenge: Functions

Get immediate access to this and 4,000+ other videos and books.

Take your career further with a Kodeco Personal Plan. With unlimited access to over 40+ books and 4,000+ professional videos in a single subscription, it's simply the best investment you can make in your development career.

Learn more Already a subscriber? Sign in.

Notes: 36. Functions & Return

Update Notes: The student materials have been reviewed and are updated as of October 2021.

Transcript: 36. Functions & Return

If you followed along and built the Bullseye app, you might remember writing functions like amountOff or sliderValueRounded. Both of those methods returned a value. When a function or method returns a value, once the function is called that value can be stored or used in-place.

For example, pointsForCurrentRound stored the result of amountOff to be used in an if statement.

func amountOff() -> Int {
  abs(target - sliderValueRounded())
}
  
func pointsForCurrentRound() -> Int {
  let maximumScore = 100
  let difference = amountOff()
  let bonus: Int
    if difference == 0 {
      bonus = 100
    } else if difference == 1 {....

And amountOff subtracted the result of sliderValueRounded from a target value.

func sliderValueRounded() -> Int {
  Int(sliderValue.rounded())
}

func amountOff() -> Int {
  abs(target - sliderValueRounded())
}

To make the printPassStatus function return something I first need to add the return token after the parenthesis

...) -> {...
  • The return token is just a dash and a greater than sign put together.

Then I’ll add the type of the value I want to return. In this case, I just want a boolean.

...) -> Bool {... 

That’s step one! Step two is to use a return statement inside of the function body. Just use the word “return” followed by whatever value you want to return.

  return grade >= lowestPass
  • The type of the value you return must match the type specified in the function declaration.

  • In this case, I just want the result of this expression, which is a bool.

In previous versions of Swift, the return keyword was required. Now, you only need it if the body of your function is longer than one line. If the body of your function is one line long, you can leave off the return and the result of that line will be implicitly returned for you.

grade >= lowestPass

Now that this function returns a boolean instead of printing something to the console, it needs a new name.

Most of the code you’ve written in this course has represented nouns like students, pets, grades, pastries, and temperatures. Functions represent tasks or actions. They’re bits of code that do something.

That action can be represented by using a verb in the function name. printHighestGrade prints the highest grade to the console. In Bullseye, startNewGame starts a new game.

But, if you recall the method examples from Bullseye, amountOff and pointsForCurrentRound are named for the values they return. When you call those methods, you get the amount off or the points for the current round. Naming functions or methods for the values they return is a common convention.

Another common convention is to add a verb like “get” or “make” or “calculate” to function names, like getPointsForCurrentRound or calculateAmountOff.

If you’re working with a team, they may have naming conventions for you to follow. If you’re your own boss, how you name your functions is another stylistic decision you have to make. In either case, staying consistent can make it easier to read and reason about your code in the future.

To give you some variety, though, I’ll rename this function in the verb style: “getPassStatus”

func getPassStatus

Now I can call that function and store the result. I’ll use the tuples at the top of this playground page for the grades.

let chrisPassStatus = getPassStatus(for: chris.grade)
let samPassStatus = getPassStatus(for: sam.grade)

I could also check to see if the whole class passed, using the returned values directly in an expression:

let classPassStatus = getPassStatus(for: chris.grade) && getPassStatus(for: sam.grade)

That Chris character is dragging the whole class down! 🙀

As you’re learning about returning values, there is one more use of the return keyword you should know about. While we’re at it, I’ll also show you one more way to deal with optionals, and how to store the type of a tuple.

Take a look at these two tuples representing our students. I’ve just left the pet value out of Sam’s tuple, but what if I want to express that Sam doesn’t have a pet, here? If I just add a pet value and set it to nil,

let sam = (name: "Sam", grade: 99, pet: nil)

the compiler has no idea what optional type this is meant to be. Hopefully you remember from our exploration of optionals that the solution that is to explicitly provide a type for the value.

The type annotation for a compound type, like a tuple, looks basically identical to a parameter list. You add that whole type annotation in exactly the same place you’d add a named type annotation.

let sam: (name: String, grade: Int, pet: String?) = (name: "Sam", grade: 99, pet: nil)

There’s the optional String I want to represent a pet. But that’s a lot to type, especially considering I want to use the same type information to our other student.

You can store this compound type for reuse via a typealias. A typealias is a sort of light-weight type. It lets you give a name to a compound type, or give an alternate name to an existing named type. Start with the keyword typealias, then the name you want to use and a single equals sign.

typealias Student =

Then copy the type annotation from Sam, and paste it at the end. Now I can say that both Chris and Sam are Students.

let chris: Student = (name: "Chris", grade: 49, pet: "Mango")
let sam: Student = (name: "Sam", grade: 99, pet: nil)

I can also write a function with a Student parameter. I’ll write a function that orders a collar for a student’s pet, but only if that student actually has a pet.

func orderPetCollar(for student: Student) {

}

In this next line I’ll do two new things. First, I want to make sure the student passed into the function has a pet.

You’ve already seen how to do that with if let binding and nil coalescing. There’s one more way to bind an optional value, and that’s guard let.

guard let starts out much like if let:

guard let pet = student.pet

The difference comes at the end. With guard, you always need to provide an else clause:

guard let pet = student.pet else { }

I’ve reached the second new thing, which is another way to use the return keyword.

guard let pet = student.pet else { return }

You can use the return keyword without a returning a value.

  • This will exit the function immediately, and return to executing code right after the function call.

That is exactly what I want!

  • If a student doesn’t have a pet, I don’t want to continue executing code in this function.

  • But if they do have a pet, that value has been bound to the local pet constant, and I can use it to pretend to order a personalized collar with a print statement:

print("One custom collar for \(student.name)'s pet, \(pet)!")

When I call the function and pass in chris

orderPetCollar(for: chris)

A shiny new collar is ordered for Mango. But if use the same function with sam

orderPetCollar(for: sam)

Nothing happens!

Next up, I have a challenge to help you try out everything you’ve learned about functions. After that, we’ll revisit that Student typealias and turn it into your first named type.