amalfilemons amalfilemons - 7 months ago 49
Swift Question

No candidates produce the expected result

I've looked at this answer, but since I am new to Swift and am following along code that should work from Stanford CS193's course, I'm a bit confused.

This is from an exercise that involves building a calculator. In the model I have these functions:

private func evaluate() -> Double? {
let (result, remainder) = evaluate(opStack)
return result
}

func pushOperand(operand: Double) {
opStack.append(Op.Operand(operand))
return evaluate()
}

func performOperation(symbol: String) {
if let operation = knownOps[symbol] {
opStack.append(operation)
return evaluate()
}
}


In the controller, I have these functions:

@IBAction func operate(sender: UIButton) {
if userIsInTheMiddleOfTypingANumber {
enter()
}
if let operation = sender.currentTitle {
if let result = brain.performOperation(operation) {
displayValue = result
} else {
displayValue = 0
}
}
}

@IBAction func enter() {
userIsInTheMiddleOfTypingANumber = false
if let result = brain.pushOperand(displayValue) {
displayValue = result
} else {
displayValue = 0
}
}


Next to the functions pushOperand/performOperation in the model where it says "return evaluate", I get the "no candidates for evaluate produce the expected contextual result type..." and next to the functions operate/Enter in the controller, I get "initializer for conditional type must have optional type..." next to the "let result" lines.

How do I rectify these errors and what is causing them (as the code works in the presentation given)?

Answer

To rectify your errors you must have return values for your functions specified.

This is because the way any function's declarations work is that you set the arguments ( eg for pushOperand the argument is 'operand' and it is of type Double ) and then you must also specify what the function outputs in the end ( eg for evaluate() it returns a value of type Double? optional Double). The way you specify a return type is by the syntax '-> YourType' after the init brackets (where the arguments are specified.

Now this is important because when you set a variable as the return value of a function, like you have in the line:

if let result = brain.performOperation(operation) {
        displayValue = result
    } else {
        displayValue = 0
    }

the function performOperation doesn't know that it can return a value because you haven't specified it, therefore the value of result is always going to be N/A the way the compiler sees it.

Now the if let error is a different one. Because you have not specified a return value for your functions, you also have not specified that the return value could be nil (is optional). If let requires that the value of the variable it is 'letting' could be nil.

To fix this try:

func pushOperand(operand: Double) -> Double? {
    opStack.append(Op.Operand(operand))
    return evaluate()
}

func performOperation(symbol: String) -> Double? {
    if let operation = knownOps[symbol] {
        opStack.append(operation)
        return evaluate()
    } else {
        return nil
    }
}
Comments