Introduction to Programming (CPSC 124)
—Hobart & William Smith Colleges, Spring 2015
Class Notes—February 4, 2015
Home | Syllabus | Calendar | Class Notes | Labs and Projects | General Notes |

How to delay programming concerns and finish a program anyway

A major element of successful programming is the ability to identify the various subproblems of a larger programming task, separate them into individual components of your program, and implement a partially-working program before you've solved everything. We'll call this technique delaying concerns.

The key ideas here are the following:

  1. Certain patterns in program structure occur over and over again.
  2. Implement as much of your program as you can, as soon as you can.
  3. Make sure to compile your program at each milestone in its construction, even if (especially if) you don't yet know how to solve everything.
  4. If you don't know how to compute a needed value, don't try yet. Instead, put a placeholder in your program, in the form of a variable whose value will eventually hold the correct thing. Don't worry about the fact that it doesn't work yet.

Item #1 means that you can learn to recognize when a particular pattern is likely to arise. Indeed, this skill is essential in program construction. By analogy, knowing a vocabulary of words and correct sentence construction does not give you enough to hold a substantial conversation in a foreign language. You must also know aspects of culture, history, politics, science, and art. The point is that all of these things are ideas that exist independently from any particular language.

Item #2 is a technique for managing that feeling of being overwhelmed by a programming problem. By committing to your code those parts of it that you do know how to build, you free yourself from the mental burden of managing complexity you don't really need to manage.

Item #3 is related closely to #2. Remembering the right syntax of a language construct is one of the hardest things that beginning programmers face. You absolutely must avoid mixing this challenge in with the challenge of actual problem solving. If you make sure that you have a program free of syntax and type errors at every step, you don't need to think about these things any more. The code you have written can then help you to think through the remaining problems, rather than obscuring them.

Item #4 is the core of this technique, because it deals with the places where you get stuck. The idea here is to ignore the fact that you're stuck, in order to make progress through the rest of the program construction. Instead, just think about the simplest possible version of the stuck problem: what type(s) of value(s) do you need? For each such type, declare a variable of that type, giving it some value that will get it past the compiler. It doesn't have to work yet! You'll come back and solve that problem later.

Example

In Lab 1, you encountered a program that solves the following problem: write a program that takes arguments representing the ambient temperature and the observed wind speed (in that order). The program should print the perceived temperature, adjusted for windchill.

Example interaction

John-Lasseter:~ jlasseter$ java Windchill 45.3 20.2
37.391697636353825

The Pattern

As with almost every program involving command-line arguments, this program follows a pattern of input gathering/processing/output. In other words, our program will consist of three stages: reading the contents of the arguments array, computing the answer, and printing the result. We know there will be two arguments, and that both of them will be double values. We know that the first of those will represent the temperature and that the second will be the wind speed. Let's get that much down, along with the boilerplate code:

public class Windchill {
    public static void main(String[] args) {
        double temp = Double.parseDouble(args[0]);
        double wind = Double.parseDouble(args[1]);
        
        // processing code goes here
        
        // output code goes here
    }
}

See what we just did? Now we've got the input task solved. Maybe not completely or as robustly as we'd like, but it will certainly do for now.

Now we know that we'll need to print out the perceived temperature, but we don't know how to calculate that yet. What we can work out quickly is that there is one value to calculate, and that it will be a number, where we care about the integer and fractional components. That means a double. Pick a variable to store the result, and add a declaration for it:

public class Windchill {
    public static void main(String[] args) {
        double temp = Double.parseDouble(args[0]);
        double wind = Double.parseDouble(args[1]);
        
        // processing code goes here
        double wtemp = 0.0;   
        // PROTOTYPE: completely bogus, but it makes progress
        
        // output code goes here
        System.out.println(wtemp);
    }

}

Finally, how do we actually calculate the value of wtemp? This doesn't have an obvious answer at all. In fact, it requires some domain-specific knowledge from mathematical modeling. For our purposes, the answer is "the internet knows"! There are actually several choices for this. The US customary units formula is

The point here is that, having coding all the things that aren't this formula, our only remaining problem is to code this formula. Since this lab was also your first and only exposure to the Math library (see the General Notes section of our web site), this was more challenging than it will become with some practice. Here's the completed program:

public class Windchill {
    public static void main(String[] args) {
        double temp = Double.parseDouble(args[0]);
        double wind = Double.parseDouble(args[1]);
        
        // processing code goes here

        double wtemp = 35.74 + 0.6215*temp - 35.75 * Math.pow(wind,0.16)
                        + 0.4275 * temp * Math.pow(wind,0.16);
        
        // output code goes here
        System.out.println(wtemp);
    }

}

which, with a bit of algebraic simplification (not necessary, but nice practice) is

public class Windchill {
    public static void main(String[] args) {
        double temp = Double.parseDouble(args[0]);
        double wind = Double.parseDouble(args[1]);
        
        // processing code goes here
        double v2 = Math.pow(wind,0.16);
        double windchill = 35.74 + 0.6215*temp 
                            + (0.4275 * temp  - 35.75) * v2;
        
        // output code goes here
        System.out.println(wtemp);
    }

}

Not every program you write will have such a clear-cut structure. In fact, almost none of them will after the next couple of weeks. Yet even in programs of substantial complexity, some of these patterns arise over and over again. Think about the javac program, for example: it reads the name of a file from a command-line argument, does stuff with that file name internally, and prints out error messages, for all the errors it finds. Though there's a huge amount going on behind that program, you can see the same input/processing/output pattern at work!


John Lasseter