Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

iOS Swift Functions and Optionals Optionals What is an Optional?

if let culprit = findApt("505"){}

I don't understand how this will execute. By typing

let culprit = findApt("505")

culprit will either have a String value or nil (in this case it would be nil). However, how does this evaluate to a boolean expression. And same goes for if we typed

let culprit = findApt("404")

which would return a String value "404". This does not evaluate to a boolean expression either.

So why does if let culprit = findApt("505"){}execute?

Can someone help me clear up this confusion?

3 Answers

Nathan Tallack
Nathan Tallack
22,159 Points

Oh right. You are asking about the conditional assignment.

Right.

So String? is a different type to String. It is actually an Optional<String> type that has two enumeration cases in it, None and Some(T).

So when you are doing the expression if let culprit, you are using "optional binding" which finds out if the optional contains a value. Not actually a bool evaluation as such.

If you take a look in the Swift Programming Language book published by Apple there is a section in the first chapter which explains it a little better. I admit that I am taking it at face value that I can use if let as a way to unwrap an optional safely, without actually totally understanding the mechanics beneath it. I am sure if we saw the class definition for the Optional<String> we would see a method that shows how that works.

Ok that's alright. Thank you for taking your time to explain as much as you did :)

Nathan Tallack
Nathan Tallack
22,159 Points

Yeah, this is a little confusing. Let's walk through it.

func findApt (aptNumber : String) -> String {
    let aptNumbers = ["101","202","303","404"]
    for tempAptNumber in aptNumbers {
        if ( tempAptNumber == aptNumber) {
            return aptNumber
        }
    }
}

Let's first understand what happens when you are passing "505" into the above function where we have declared the function to return a String type. So in the this scenario your conditional return will never happen. This is what causes the compile error.

So what we could do is have a return outside of the for loop that will return the empty string as the video described. But as described this could break other things, such as with the bool evaluation example.

So this is where the nil return comes into it. But remember, you can't assign nil to a String type. You need to have an optional String type (that is String?). So your function can be defined now with the optional return. Looks like this now.

func findApt (aptNumber : String) -> String? {
    let aptNumbers = ["101","202","303","404"]
    for tempAptNumber in aptNumbers {
        if ( tempAptNumber == aptNumber) {
            return aptNumber
        }
    }

    return nil

}

In this case we are return a nil with your 505. So if you assign that to a value like the example given, but you always take care with with functions that can return nil and safely unwrap it. Remember, unwrapping is putting the ! on the end of your value to say "I know this could be nil and am ready for it!". So you use the function like this.

if let culprit = findApt("505") {
    print("Apt Found")
}

This is the "safety" that is built into swift. You are making a function that you know can return a nil value. You are using that function in a way that checks to see if nil is returned (the "if let" example). That way you will never have your code crash because it expected data to be where there was none.

So, in short, these are your rules.

  • If your function has a return value, all possible outcomes must return a value.
  • If your function has outcomes that have no value to return use nil with an optional return (the ?).
  • If you are using a function that could return a nil value (an optional return) you need to unwrap it (the !).
  • If you are unwrapping something always do it safely (such as with the "if let" conditional).

I hope this helps. :)

Hi Nathan, I understood everything you said. I also understand that if let unwraps your optional value. But my question still remains. How is let culprit = findApt("505") in the if statement condition a boolean expression?

Nathan Tallack
Nathan Tallack
22,159 Points

That is the thing. It is not a condition against a bool. If let against an optional performs an optional binding action. It must be something built into the type that overrides the expected bool action.

Just like you can write your own overrides within a class to change what + and - and == do, I am sure they wrote some kind of override inside the Optional type to change what the if let does against it. Being that if there is an Optional enumeration value or a nil value in the enumeration of the Optional.

In short, it is not a traditional bool expression. It is an optional binding expression. It just reads like a bool conditional would. :)

Oh, are you positive about that? In that case, this makes so much more sense! Thanks so much!

Nathan Tallack
Nathan Tallack
22,159 Points

Not positive. Still very much a newbie. But I know you can override operators in classes, and know that the Optional type has a special case for the "if let" condition which has its own chapter in the manual and it's own name (optional binding).

So without seeing the actual implementation of the class (would likely be beyond my ability to understand even if I did see it) I cannot say for sure.

Perhaps one of the more qualified people here on the forum will see this thread and chime in. :)