Assignment II - programmable calculator

266 views
Skip to first unread message

jonathan.nyc

unread,
Nov 21, 2011, 1:31:26 PM11/21/11
to iPhone Application Development Auditors
I'm working on Assignment II, and some of the requirements is not
clear to me. Maybe that's because I've never used a programmable
calculator.

The sheet requires us to parse RPN input into a readable expression.
What is the input sequence that instructs the device to define that
input as a program? How are variable values plugged into the
function?

The instruction sheet doesn't seem to specify these parts of the
requirements. Can anyone help here?

Thanks,
Jonathan

jonathan.nyc

unread,
Nov 21, 2011, 3:34:47 PM11/21/11
to iPhone Application Development Auditors
I'll answer my own question. Part 3.e requests preset values for each
test button.

I'm not used to requests to hard-code.

Rob Todd

unread,
Nov 21, 2011, 1:58:47 PM11/21/11
to iPhone Application Development Auditors
Jonathan,
I had the exact same questions and ended up going back to one of the
previous "assignment 2" sheets to get a better interpretation of which
way to go. I ended up creating a system that, in addition to the
variable buttons, I have "Store" and "Solve" button. The Store button
takes whatever is in the display and forms a (NSSet *) with whichever
variable is pressed (i.e. 36 E Store X would store 36 in variable X)
and passes that (NSSet *) to the brain. The Solve button simply takes
the impression on the top of the stack (which gets passed operand by
operand in to the brain) and evaluates it... so "36 E 12 +" would do
nothing except push the operands on to the stack but once the Solve
button is pressed, the brain gets told to evaluate the expression and
the result comes back.

I'm sure there are better ways to solve this problem but this one
about the only way I could think of doing it quickly.

Rob

Rob Todd

unread,
Nov 21, 2011, 1:52:18 PM11/21/11
to iphone-appd...@googlegroups.com
Jonathan,
I had the exact same questions and ended up going back to one of the previous "assignment 2" sheets to get a better interpretation of which way to go. I ended up creating a system that, in addition to the variable buttons, I have "Store" and "Solve" button. The Store button takes whatever is in the display and forms a (NSSet *) with whichever variable is pressed (i.e. 36 E Store X would store 36 in variable X) and passes that (NSSet *) to the brain. The Solve button simply takes the impression on the top of the stack (which gets passed operand by operand in to the brain) and evaluates it... so "36 E 12 +" would do nothing except push the operands on to the stack but once the Solve button is pressed, the brain gets told to evaluate the expression and the result comes back.

I'm sure there are better ways to solve this problem but this one about the only way I could think of doing it quickly.

Rob

> --
> You received this message because you are subscribed to the Google Groups "iPhone Application Development Auditors" group.
> To post to this group, send email to iphone-appd...@googlegroups.com.
> To unsubscribe from this group, send email to iphone-appdev-aud...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/iphone-appdev-auditors?hl=en.
>

Craig March

unread,
Nov 22, 2011, 2:48:40 AM11/22/11
to iphone-appd...@googlegroups.com
Correct, use static values for your variables.

Had the same "huh" moment myself.

--
Craig
Sent from my mobile

Duane Bender

unread,
Nov 22, 2011, 8:47:06 AM11/22/11
to iphone-appd...@googlegroups.com
It's good to see there are others on this group working on the new Fall 2011 course and assignments. I watched the first two lectures and am working on Assignment 1. I'll try to catch up.

Duane

will

unread,
Dec 4, 2011, 6:30:21 PM12/4/11
to iPhone Application Development Auditors
Hey all,

I'm finishing up the second assignment, and am curious how others went
about a few points.

(1) According to hint #3, descriptionOfTopOfStack: should be less than
20 lines of code. I don't see how that's possible, considering all
the special cases you need to consider for parenthesis. Just the +/-
case requires 5-6 lines of code: the first if statement, then two more
conditionals and dealing with if the operand already as a "-" in
front.

(2) According to question #3c, the variable values dictionary should
be a property of the controller. Since we want
runProgram:usingVariableValues: to take this dictionary as an
argument, performOperation:operation also needs to take variableValues
as an argument; this seems messy. Does anyone know why variableValues
shouldn't just be a property of CalculatorBrain, instead?

(3) In question #4, we're told to remove the last element of the stack
(if userIsInTheMiddleOfEnteringNumber==NO). Since the stack may look
like: "3 8 +", removing the last element just causes the display to
show "8". Is this what others got as well?

Thanks,
Will

James

unread,
Dec 7, 2011, 3:26:37 PM12/7/11
to iPhone Application Development Auditors
Hi Will,

(1) I too am stumped on this one. I've been racking my brain on how
to keep it at 20 lines. Anyone else have hints on how to do this?
Without adding a bunch more lines of code, I'm not sure how to remove
extraneous parentheses.

(2) This one confused me for awhile. I did end up using a property in
the Controller and updated runProgram to this:
+ (double)runProgram:(id)program
{
return [self runProgram:program usingVariableValues:nil];
}
The reason is that the assignment states this:

"If there are variables in the specified program for which there are
no values in the specified NSDictionary, use a value of 0 for those
variables when you run the program. This should be the case if someone
calls the original runProgram: method (the one shown in the demo in
class)."

So runProgram:usingVariableValues accounts for nil and substitutes 0
in. Then when I hit any of the "test" buttons which populate my
Controller property, I call runProgram:usingVariableValues from there
and it updates the display with whatever the value is for the
variables used in the program. I'd be happy to send you the code or
post it here if others want to see it.

(3) I'm not that far yet as I'm still trying to figure out (1) :)

Regards,
James

James

unread,
Dec 8, 2011, 8:53:04 AM12/8/11
to iPhone Application Development Auditors
Hi, I just saw in another thread about posting code to the forum. My
apologies! :(

Regards,
James

James

unread,
Dec 9, 2011, 7:39:02 PM12/9/11
to iPhone Application Development Auditors
Hi Will, I finished Assignment 2 so hopefully I can answer the other
two questions correctly.

(1) I would love to see how it can be done in less than 20 lines of
code. That said, I have mine down to 28 (could be less depending on
coding style, i.e. "else" being on the same line as a closing "if"
bracket) and I only needed one "if" check for precedence. The key is
to remember what the last *operation* was as it recurses through.
This covers all the cases described in 2a through 2f in the assignment
(i.e. "π r r * *" yields "π * r * r", etc...).

(2) See my previous post, but here's a piece I left out. I do not need
to change performOperation: as it still calls runProgram:. I only
mention this because I've seen other threads where people modify that
function and it doesn't need to (the "test" buttons in the Controller
take care of that).

(3) Using your example, "3 8 +", hitting Undo also updates my display
back to 8 instead of 11 and my descriptionOfProgram output updates to
"8, 3" instead of "3 + 8".

I hope this helps. If you'd like, I could email the code to you
*privately*. ;)

Duane Bender

unread,
Dec 10, 2011, 7:32:50 PM12/10/11
to iphone-appd...@googlegroups.com
James, when I first read your answer here, I didn't see how it answered Will's question #2. His point (I think) was that the performOperation: instance method needs the variables dictionary to pass to the runProgramUsingVariableValues:: class method. This is done from within the model, which does not have access to a property in the controller. I've been puzzling over this same issue.

But now I see that you are calling the runProgramUsingVariableValues:: class method from the controller when a test button is pressed. (I assume your call is [CalculatorBrain runProgram:self.brain.program usingVariableValues:self.testVariableValues];?)  That certainly solves the problem Will and I had, but it also means you have taken a very different approach to the operation of the calculator than I was envisioning. I was going to have the test buttons simply populate the testVariableValues dictionary and update the currentVariableValues label, all done within the controller. (Prior to pressing a test button, the dictionary would be nil and the label blank.) Whenever an operation button is pressed, the controller would invoke the model's performOperation: method, which would in turn call the runProgramWithVariableValues:: class method. And that is where the problem lies, as Will pointed out.

I guess I'll head down the path you took and use the test buttons to run the program.

Duane

Duane Bender

unread,
Dec 10, 2011, 7:35:14 PM12/10/11
to iphone-appd...@googlegroups.com
edWill, did you end up calling the runProgram:withVariableValues: class method from the controller, when a test button is pressed, as James did? Or did you find a way to run the program when an operation is pressed?

Duane

Duane Bender

unread,
Dec 10, 2011, 7:52:25 PM12/10/11
to iphone-appd...@googlegroups.com
Another question on Assignment 2: When should we call the descriptionOfProgram method? Do we call it every time our controller sends something to the model, similar to the way we built an expression on the display in RPN in Assignment 1?  Or do we leave it in RPN as we enter operands, and call the descriptionOfProgram method when we perform an operation? Or do we leave it in RPN until we run the program, and then run that method to switch the display to in-fix notation?

Duane

James

unread,
Dec 11, 2011, 11:16:12 AM12/11/11
to iPhone Application Development Auditors
Hi Duane,

My point was that performOperation: didn't need the variables
dictionary. It remains unchanged from the Demo lecture. It calls the
runProgarm: class method and runPrgram: calls
runProgram:usingVariableValues. Since performOperation: and
runProgram: don't have the dictionary, runPorgram: passes nil to
runProgram:usingVariableValues. At least that's how I (eventually)
interpreted this from the assignment:

"If there are variables in the specified program for which there are
no values in the specified NSDictionary, use a value of 0 for those
variables when you run the program. This should be the case if someone
calls the original runProgram: method (the one shown in the demo in
class)."

So the testVariableValues dictionary will then always produce 0 values
(as handled in the runProgram:usingVariableValues class method)
*until* a user presses one of the "test" buttons.

Regarding calling runProgram:usingVariableValues, that is exactly what
I do inside the "test" button IBAction. My original implementation
was exactly how you described. It simply populated the property in the
Controller and updated the label. However, I couldn't think of a way
to keep the model backwards compatible (which I assume the instructor
wanted) without modifying performOperation: to something like
performOperation:usingVariableValues or creating a property in the
model to hold its own testVariableValues and providing an instance
method to set it. I also considered changing operationPressed: in the
Controller to call runProgram:usingVariableValues. I didn't like any
of these ideas, though, as it didn't seem like it's what the
instructor would have wanted.

My final implementation is that I have an updateDisplay: method in the
Controller that handles updating the program description, updating the
testVariableValues label, and handling the display label when Undo is
pressed. I call updateDisplay: from within my testPressed:,
undoPressed:, enterPressed:, variablePressed:, and operationPressed:
IBActions.

I hope this helps!

Regards,
James

will

unread,
Dec 11, 2011, 11:26:45 AM12/11/11
to iPhone Application Development Auditors
James/Duane,

Thanks for your comments.

My solution was to change performOperation: to
performOperation:withVariableValues:, and just pass in the values
dictionary there. It didn't seem the cleanest way, but it works just
fine.

As for the descriptionOfProgram method, I created an updateDescription
method in my controller which calls descriptionOfProgram. I have it
called whenever the display setter or clearPressed is called.

Thanks,
Will

Duane Bender

unread,
Dec 11, 2011, 1:14:35 PM12/11/11
to iphone-appd...@googlegroups.com
Honestly, it seems to me that the best (in an MVC sense) approach would be to have the testVariableValues dictionary be a property of the model rather than of the controller. The controller would have access to it, both to set the values and to use them for display purposes as needed. If a controller (like the one from Assignment 1) didn't use variables, the model would still work with a nil dictionary. But I guess I'll follow the instructor's directions, mainly because it may make things easier in later assignments. As I said before, I think I'll go with calling runProgramWithVariableValues:: from the testPressed method in the controller, as James did.  Will's approach is still valid, as long as the altered model would still work with the Assignment 1 controller, as backward-compatibility was a requirement.

Thanks, James and Will, for the feedback.

Duane

dimi

unread,
Dec 11, 2011, 5:07:48 PM12/11/11
to iphone-appd...@googlegroups.com
hello All,

total objective c niewbie here ... coming from c++

I so far understood how the controller has to have (or may) a dictionary with test values.
But when i examined Task3.c "change your calculator to update its display by calling your new runProgram:usingVariableValues"  i was really puzzled:

How can the controller call the calculatorbrain to runProgram as the later expects a program as an argument, which isn't (?) accessible from the Controller.
Is one supposed to get the program description and make up program from that?

any hints would be greatly appreciated


Duane Bender

unread,
Dec 11, 2011, 8:32:58 PM12/11/11
to iphone-appd...@googlegroups.com
Remember that program is a public @property of the CalculatorBrain class, and that your controller's brain @property is an instance of that class. So from your controller, you can use self.brain.program to access program.

Duane

dimi

unread,
Dec 12, 2011, 4:32:42 AM12/12/11
to iPhone Application Development Auditors
Hi Duane,

many thanks for the tip! I'm not yet comfortable with the notation
Objective C offers..
I'll try that.

I am still puzzled by the fact that a "program" is made up with
instance information.
I thought I read that class methods should not give access to instance
data.
Have I gotten it completely wrong or do any others also see that as a
conceptual problem?

Warm regards
Dimi

Duane Bender

unread,
Dec 13, 2011, 11:15:01 AM12/13/11
to iphone-appd...@googlegroups.com
There are probably others here who could better explain this, but here goes. What you probably read is that a class method cannot use instance variables. That's because only an instance of a class HAS instance variables, because the memory locations that hold instance variables are allocated at the time the instance is allocated. So what you don't want to see is a class method implementation that includes references to that class' instance variables. Now in the case above, you have an instance of the CalculatorBrain class (called brain). It has an @property called program with getters and setters for an instance variable called _program.

Now let's look at the following statement:


       [CalculatorBrain runProgram:self.brain.program usingVariableValues:self.testVariableValues];

Here, we're calling a class method (runProgram:usingVariableValues:) and passing its required parameters. The first of those parameters (self.brain.program) is an array. The fact that we get this array from our own instance (brain) of a CalculatorBrain is unknown and immaterial to the class method; it needs an array and it gets one. The second parameter is a dictionary we get from our controller's testVariableValues @property. Now inside your runProgram:usingVariableValues class method, there should be no references to _program or self.program. The program array it works with is the one it received from the caller, not one contained in its own _program instance variable.

So:

"I am still puzzled by the fact that a "program" is made up with instance information."

The "program" used by the class method is any array that is passed to it by a caller. You know that in our project this array is coming from an instance variable within an instance of CalculatorBrain, but this class method does not know this and does not care.

"I thought I read that class methods should not give access to instance data."

Your class method is not giving access to any data at all. It returns a double value that it calculates. It's brain, your instance of CalculatorBrain, that is giving access to the instance data, and it's giving it to the controller that owns it.

Hope that helps.

Duane

jonathan.nyc

unread,
Dec 13, 2011, 1:47:46 PM12/13/11
to iPhone Application Development Auditors
I'm looking into the same question. If program is a public property,
then that's a good solution.

I don't see any instructions allowing us to include program in the
public API. Did I miss something?

I can code this on my own, but I'd feel better if I know I'm complying
with the expectations of the assignment.

Jonathan

dimi

unread,
Dec 13, 2011, 4:24:13 PM12/13/11
to iphone-appd...@googlegroups.com

Hello Doug,
I sincerely appreciate all the effort in explaining this.
I do understand the concept of "the controller needs an array and gets it".

I guess the bottom line question is: why not get a program through an instance method, since the program is always filled with instance data and the controller always holds an instance of the model.
But, again, this might be the professor's way to force one to think about accessing class/instance data.

Jonathan,
in the first paragraph of the required tasks, there's an instruction about exposing a
+ (double) runProgram:(id)program class method from the CalculatorBrain public API

moreover there's the additional instruction to add the following class method in the same API.
+ (double) runProgram:(id)program usingVariableValues:(NSDictionary *)variableValues;

So there's no doubt, that the intention is to proceed in this way. The program stack can only be evaluated (following this assignment's rules) by getting it through the public property of the CalculatorBrain.
Maybe I confused you with my conceptual question. The requirements though could take some re-writing.
warm regards
dimi

jonathan.nyc

unread,
Dec 13, 2011, 9:33:21 PM12/13/11
to iPhone Application Development Auditors
Dimi,

You've pointed me to the first paragraph, which does answer my
question, but not exactly in the way you described.

The "@property (readonly) id program;" requirement explains how
program is to be accessed!

Jonathan

Timm

unread,
Dec 14, 2011, 5:07:17 PM12/14/11
to iPhone Application Development Auditors
Hi guys.

I'm having a bit of trouble figuring out all of this precedence
nonsense, and where to put those parentheses.
James mentioned that the trick was to remember what operation came
before the current one. However, I just can't fathom a way to do that.
Of course, you'd make some methods that do this, but I don't know what
exactly they would do. James said he only needed one check for
precedence, and that baffles me further.

So far I've got my descriptionOfTopOfStack:, which scoops out how many
operands an operation takes and from then on I format the result. If
the operation needs two operands I pass it to, the self made method,
descriptionForTwoOperandOperation:firstOperand:secondOperand:, if it
needs one then on to descriptionForOneOperandOperation:operand:.

Now these two methods should in some way remember the last operation
that was passed to them or figure out if parentheses are needed or
not. I just can't put my brain where my code is (or ought to be).

If any of you could help, it would be much appreciated.

James

unread,
Dec 15, 2011, 9:44:31 AM12/15/11
to iPhone Application Development Auditors
Hi Timm,

You could keep track of the last operation by using a static variable
within descriptionOfTopOfStack: or change the method signature to
something like descriptionOfTopOfStack:lastOperation:. The first call
to it would pass nil for lastOperation and subsequent calls would pass
topOfStack (assuming topOfStack was an operation) as it recurses.
Once you know the current and previous operations, an if check against
them would tell you if you need parentheses or not.

Hope that helps.

Regards,
James

Timm

unread,
Dec 15, 2011, 12:38:56 PM12/15/11
to iPhone Application Development Auditors
Thanks James! Assignment 2 is done for me. I with everybody else good
luck, and I hope you make it too.

PS. Though Paul said you could implement the changes by adding around
50 lines of code, I certainly have gone over that amount. I guess I
could start shaving some lines off of it now...
How many lines do you guys implement fit in?

Reply all
Reply to author
Forward
0 new messages