0

I'm grinding through Apple's App Development with Swift book and I have been having a few issues with the Optionals sections.

I'm getting stuck accessing a dictionary after I have accessed another dictionary to return an optional value that meets a condition. The error being returned is:

Missing return in a function expected to return 'Double?'

var prices = ["Chips": 2.99, "Donuts": 1.89, "Juice": 3.99, "Apple": 0.50, "Banana": 0.25, "Broccoli": 0.99]
var stock = ["Chips": 4, "Donuts": 0, "Juice": 12, "Apple": 6, "Banana": 6, "Broccoli": 3]

func priceCheck(name: String) -> Double? {
    let pricefinder = name
    if let name = stock[name] {
        print(name)
        if name > 0 {
            if let pricefinder = prices[pricefinder] {
                print(pricefinder)
                return pricefinder
            } else {
                return nil
            }
        }
    } else {
        return nil
    }
}

Where am I going wrong with the code above? I need to check if a product is in stock and then return its price if that condition evaluates to true.

And is there a more elegant solution?

3 Answers 3

5

Your function can be shortened a hell of a lot by taking advantage of some of the tools that’s Swift gives you. Here, take a look, this does the same thing...

func priceCheck(name: String) -> Double? {
    guard let stockAmount = stock[name],
        stockAmount > 0,
        let price = prices[name] else {
        return nil
    }

    return price
}
Sign up to request clarification or add additional context in comments.

5 Comments

That prices[name] unwrap is not needed, you can directly return prices[name].
Mentioned as an alternative approach in my answer :)
@Sulthan true. Guess it depends how the OP wants to handle the missing price. But yes, you’re right :-)
Thanks @Fogmeister this is really good. I just checked the book and there's a whole section on using guard with optionals that helped unpack this concept for me.
@RhysEdwards no worries. Happy to help. Never stop learning :-)
2

The problem is merely that you have not covered all cases in your logic. What if name is not greater than zero? Your code does not say what to do. Thus you fail to return a value in that situation:

func priceCheck(name: String) -> Double? {
    let pricefinder = name
    if let name = stock[name] {
        print(name)
        if name > 0 {
            if let pricefinder = prices[pricefinder] {
                print(pricefinder)
                return pricefinder
            } else {
                return nil
            }
        } else { // this is the question: what if it isn't?
            return nil // ???? I don't know what you want to do...
            // ... but you MUST return something in this situation
        }
    } else {
        return nil
    }
}

Listen to the compiler. It knows more than you do.

Comments

2

As a pretty quick solution, all you have to do is to add return nil at the end of your function:

func priceCheck(name: String) -> Double? {
    let pricefinder = name
    if let name = stock[name] {
        print(name)
        if name > 0 {
            if let pricefinder = prices[pricefinder] {
                print(pricefinder)
                return pricefinder
            } else {
                return nil
            }
        }
    } else {
        return nil
    }

    // here we go:
    return nil
}

because at some point (name is not greater than 0), the function does not returns anything.

Also, note that you could implement your function -as a shorter version- as:

func priceCheck(name: String) -> Double? {
    let pricefinder = name
    if let name = stock[name], name > 0 {
        if let pricefinder = prices[pricefinder] {
            return pricefinder
        }
    }

    return nil
}

If the function returns nil at the end of it, there is no point of adding else { return nil } for each if; Or you could even use guard statement to achieve it as mentioned in Fogmeister`s answer.

4 Comments

If you are going to add a "catch all" return nil at the end, then I suggest removing all of the redundant else { return nil } statements. Only have the return pricefinder that returns a real value and the one "catch all" return at the end.
Yes @rmaddy, that's exactly what I mentioned in my update :)
There are a few other confusing things about the OP's code that could use some cleanup. The function's parameter is called name but then a new name constant is introduced in the first if let. And pricefinder is needlessly copied from the original parameter due to the confusing 2nd name constant.
you can just return prices[pricefinder] and invert the condition: guard let name = stock[name], name > 0 else { return nil }

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.