Please note, this blog entry is from a previous course. You might want to check out the current one.
Enhance your application to show the user error conditions like divide by zero, square root of a negative number, and insufficient operands. One way to do this (and to get more experience with using id) might be to have runProgram:usingVariableValues: in CalculatorBrain return an id (instead of a double) which is an NSNumber with the result or an NSString with the description of an error if it encounters one. Then update your Controller to use introspection on the return value and display the appropriate thing to the end-user.
Mainly the API of the CalculatorBrain has to be changed from double to id:
- (id)performOperation:(NSString *)operation; - (id)performOperation:(NSString *)operation usingVariableValues:(NSDictionary *)variableValues; + (id)runProgram:(id)program; + (id)runProgram:(id)program usingVariableValues:(NSDictionary *)variableValues;
The biggest change is necessary in popOperandOffStack because if we return error messages, we want to keep them and not overwrite them with something else in the program and we have to format the result at the end to NSNumber:
+ (id)popOperandOffStack:(id)stack { double result = 0; id topOffStack = [stack lastObject]; if (topOffStack) [stack removeLastObject]; if ([topOffStack isKindOfClass:[NSNumber class]]) { result = [topOffStack doubleValue]; } else if ([topOffStack isKindOfClass:[NSString class]]) { NSString *operation = topOffStack; id firstOperand; double firstNumber; id secondOperand; double secondNumber; if ([self isTwoOperandOperation:operation]) { firstOperand = [self popOperandOffStack:stack]; if ([firstOperand isKindOfClass:[NSString class]]) return firstOperand; secondOperand = [self popOperandOffStack:stack]; if ([secondOperand isKindOfClass:[NSString class]]) return secondOperand; firstNumber = [firstOperand doubleValue]; secondNumber = [secondOperand doubleValue]; } if ([self isSingleOperandOperation:operation]) { firstOperand = [self popOperandOffStack:stack]; if ([firstOperand isKindOfClass:[NSString class]]) return firstOperand; firstNumber = [firstOperand doubleValue]; } if ([operation isEqualToString:@"+"]) result = firstNumber + secondNumber; else if ([operation isEqualToString:@"*"]) result = firstNumber * secondNumber; else if ([operation isEqualToString:@"-"]) result = secondNumber - firstNumber; else if ([operation isEqualToString:@"/"]) { if (!firstNumber) return @"division by zero"; result = secondNumber / firstNumber; } else if ([operation isEqualToString:@"sin"]) result = sin(firstNumber); else if ([operation isEqualToString:@"cos"]) result = cos(firstNumber); else if ([operation isEqualToString:@"sqrt"]) { if (firstNumber < 0) return @"sqrt of negative number"; result = sqrt(firstNumber); } else if ([operation isEqualToString:@"π"]) result = M_PI; else if ([operation isEqualToString:@"+/-"]) result = -firstNumber; } return [NSNumber numberWithDouble:result]; }
And a minor change in the controller, where we change the output formating from %g for doubles to %@ for NSNumbers and NSStrings.
self.display.text = [NSString stringWithFormat:@"%@", [CalculatorBrain runProgram:self.brain.program usingVariableValues:self.testVariableValues]];