Calculator Brain Assignment 2 Operations

Add two new buttons to your Calculator’s UI: →M and M. Don’t sacrifice any of the required operation buttons from Assignment 1 to add these (though you may add yet more operations buttons if you want). These two buttons will set and get (respectively) a variable in the CalculatorBrain called M.
a. →M calls evaluate in your Model with a Dictionary which has a single entry whose key is M and whose value is the current value of the display, and then updates the display to show the result that comes back from evaluate. Until this button (or the clear button) is pressed again, this same Dictionary should be used every time evaluate is called.
b. →M does not perform setOperand.
c. Touching M should setOperand(variable: “M”) in the brain and then show the
result of calling evaluate in the display.
d. →M and M are Controller mechanics, not Model mechanics (though they both use
the Model mechanic of variables).
e. This is not a very great “memory” button on our Calculator, but it can be used for testing whether our variable function implemented in our Model is working properly. Examples …
9 + M = √ ⇒ description is √(9+M), display is 3 because M is not set (thus 0.0).
7 →M ⇒ display now shows 4 (the square root of 16), description is still √(9+M) + 14 = ⇒ display now shows 18, description is now √(9+M)+14

Start by adding the two new buttons:

Though this actually a view-controller task, I had a tiny bug in the last task – so change the brain to show the symbol of the variable as description:

func evaluate(using variables: Dictionary<String,Double>? = nil) -> (result: Double?, isPending: Bool, description: String) { ... case .variable(let symbol): if let value = variables?[symbol] { accumulator = (value, symbol) } else { accumulator = (0, symbol) } ... }

We need something to store the variables:

private var variables = Dictionary<String,Double>()

Currently show the result of the calculation only from the perform-operation method. Because we will need to do this in different places move that part of the code into a new private method. Don’t forget to use the variables now for the evaluation:

private func displayResult() { let evaluated = brain.evaluate(using: variables) if let result = evaluated.result { displayValue = result } if "" != evaluated.description { descriptionDisplay.text = evaluated.description.beautifyNumbers() + (evaluated.isPending ? "…" : "=") } else { descriptionDisplay.text = " " } } @IBAction func performOperation(_ sender: UIButton) { ... displayResult() }

Now link the two (or four) new buttons to two new actions. One time we just set the variable value in the view controller, the other time we push it to the calculator brain. Both times we update the display – and tell the controller, that the user is not in the middle of typing any more:

@IBAction func storeToMemory(_ sender: UIButton) { variables["M"] = displayValue userIsInTheMiddleOfTyping = false displayResult() } @IBAction func callMemory(_ sender: UIButton) { brain.setOperand(variable: "M") userIsInTheMiddleOfTyping = false displayResult() }

It is actually task 9 but it makes testing a little bit easier:

@IBAction func reset(_ sender: UIButton) { ... variables = Dictionary<String,Double>() }

The complete code for the assignment #2 task #7 is available on GitHub.

Have your calculator report errors. For example, the square root of a negative number or divide by zero. There are a number of ways to go about “detecting” these errors (maybe add an associated value to the unary/binaryOperation cases which is a function that detects an error or perhaps have the function that is associated with a unary/binaryOperation return something that is either an error or a result or ???). How you report any discovered errors back to users of the CalculatorBrain API will require some API design on your part, but don’t force users of the CalculatorBrain API to deal with errors if they don’t want to (i.e. allow Controllers that want to display errors to do so, but let those that don’t just deal with NaN and +∞ appearing in their UI). In other words, don’t break any callers of the API described above (who don’t care about errors) to support this feature (i.e., add methods/ properties as needed instead). You are allowed to violate Required Task 11 to implement this Extra Credit item, but not Required Task 1 (you can enhance that data structure, but not switch to a new one).


Leave a Reply

Your email address will not be published. Required fields are marked *