Monday, February 23, 2009

Challenge One: Bergin Swing Calculator

During the time between 2005-2009 I began my software design courses with a problem I call the “Bergin Calculator Problem” (Inspired by Joe Bergin’s Polymorphic Calculator). It requires the student to program a simple calculator with only six buttons. Three number buttons (2,3,5) , two operator buttons (+,-) and an equals button. The calculator need only perform one binary operation before yielding an answer following a strike on the equals button. A typical computation would involve entering 2, 2, +, 3, 3, = … and the display would indicate the answer of 55. The display would show the numbers entered in both the pre-operator and post-operator modes, but not the operator itself. Thus, one would only ever see numbers in the display. Following each computation, striking the equals button would also render the calculator ready for a subsequent computation with an entirely new set of numbers.
Over ninety per cent of the submissions I graded used conditional logic to solve the problem. The week following, the class would go through the problem and together, construct a calculator that uses no conditional logic nor loop structures. The fact that this exercise amazes many students, indicates the very real possibility that most have been taught how to use an object-oriented language to do procedural programming - a very easy thing to do. In fact, I recall one graduate student who had taken the problem back to his work place and one of his co-workers, literally a rocket scientist, said the problem couldn’t be solved without the use of if’s. Since then, I have taken to giving problems to students that require them to produce a solution not dependent on conditional logic – I call this “Programming without if’s.”
I will discuss in another place the problem of over-engineering but for now assume it’s OK, in fact desirable, to construct an over-engineered solution. Why? The metaphor I like to use is that of the toolbox. When you go to your toolbox and see only a hammer, then every problem appears to be a nail. Most contemporary programmers were taught by procedural programmers whose only adaptation to learning object-oriented programming was to begin using an object-oriented language. One way to break out of this mental trap is to solve some problems without reaching for the hammer, which in the programmer’s case is the conditional logic structure.
Do I expect programmers to avoid using conditional logic as a best practice? No, the student of programming has to understand the difference between what we do to expand our capabilities, ie., put more tools in the toolbox, and what we do when programming professionally. Programming without if’s will expand your ability to see alternatives in the power offered to you by the object-oriented paradigm. If you’d like to take the Calculator Challenge a zipped Eclipse project named SwingCalculatorWithIfs is here. I will post a solution at the same address.

5 comments:

  1. Too bad i didn't come across this when i started my career in software. I could have been proud of the code i produced which i am not today. Thanks a lot.

    ReplyDelete
  2. Great. This is really an eye opener.

    ReplyDelete
  3. This comment has been removed by the author.

    ReplyDelete
  4. This comment has been removed by the author.

    ReplyDelete
  5. You can do this without resorting to Strategy pattern and with less code. All you need to do is to keep one reference to display value rather than "firstValue" and "secondValue".

    private String display = "";//value to be displayed
    private int currentValue = 0;//current value of calculation
    private OperatorButton operator = new NullOperator();
    private boolean pre_operate_mode = true;

    //CALLED WHEN A NUMBER KEY IS HIT
    public void numberHit(int value)
    {
    display += value;
    }

    //RETURN CURRENT DISPLAY VALUE
    public String getDisplay()
    {
    return display;
    }

    //CALLED WHEN EQUALS BUTTON IS HIT
    public void operate()
    {
    currentValue = operator.operate(currentValue, Integer.parse(display));
    display = String.valueOf(currentValue));
    reset();
    }

    //CALLED WHEN AN OPERATOR BUTTON IS HIT
    public void rememberOperator(OperatorButton op)
    {
    operator = operator.replaceWith(op);
    currentValue = Integer.parse(display);
    display = "";
    }

    //RESET CALCULATOR FOR NEW COMPUTATION
    public void reset()
    {
    currentValue = 0;
    display = "";
    operator = NullOperator;
    }
    }

    ReplyDelete