600.107: Introduction to Programming

Summer Session 2006: May 30, 2006 - June 30, 2006

Assignment 3: Procedures, Functions, Methods, and all that

Out on: June 7, 2006
Due by: June 9, 2006 before noon (hard deadline)
Collaboration: None
Grading: Style 10%, Functionality 90%

Overview

Assignment 3 consists of a number of smaller programming problems again, this time involving the use of static methods to implement various functions and procedures. All previously covered concepts are of course applicable as well.

As discussed in lecture, a "function" is a method that returns a value and is therefore used as part of an expression; a "procedure" is a method that doesn't return a value and is used like an instruction. Please try to write your functions in such a way that only one return instruction at the end of your function is necessary! Please try to write your procedures without explicit return instructions!

Notes: If you have problems with any of these tasks, please contact the staff or everybody in class using the mailing lists! Do this early so you have a shot at finishing the assignment. Also, if you can't solve one problem, feel free to skip it and work on the problems you can solve. Handing in something is much better than not handing in anything. Also, please remember that we're grading you on programming style issues now (since Assignment 2 actually).

Problem 0: Refactoring Gravity (50%)

We're going to revisit the old Gravity.java program from Assignment 1 one last time. For this problem, please start with the solution we wrote in lecture.

If you look through the code again, you'll see that there are really three parts to the program. In the first part, we read some input from the user. In the second part, we do some computation to update time, velocity, and height. This is interleaved with the third part, in which we perform output back to the user.

The "input, computation, output" structure is typical of a whole class of simple applications and has been around for a long time. For this reason, there's a "traditional pattern" for these kinds of programs: split up the code according to whether it is focused on input, computation, or output. We use procedures and functions that communicate through arguments and results to effect this split.

Here is your task: Refactor the given Gravity.java program into a new NeatGravity.java program by splitting the existing code into the following pieces:

Depending on your preferences, you can either leave the task of checking that the height is valid in main(), or you can move it into readHeight(). If you do the latter, make sure that readHeight() always returns a valid height, for example by adding a loop and asking the user again and again until the height is valid.

When you have the basic program running as before again, make the following small extension: Perform two simulations each time the program is started, both using the same initial height. The first should use the Earth's gravity as before, the second should use the Moon's gravity of a = 1.622 m/s/s instead. This should only add about three lines to your program...

Important: Make sure that you keep all variables as local as possible to the place where they are needed! Your procedures and functions should communicate only through arguments and results!

Problem 1: Extreme Methods (50%)

Write a class Extreme.java that consists of five (mostly unrelated) methods:

Let me explain the "test" part a little more. What you should do is use assertions to state all the relevant properties of the functions you test. For example, if you were to test a function int one() that always returns the number 1 you would use

 assert one() == 1;

as your test. Or consider testing a function int add(int a, int b) that is supposed to return the sum of its arguments. Here you would use several test cases such as:

 assert add(0, 0) == 0;
 assert add(0, 10) == 10;
 assert add(7, 0) == 7;
 assert add(7, 12) == 19;
 assert add(1, -1) == 0;
 assert add(-1, 1) == 0;
 assert add(-1, -1) == -2;
 ...

There are "close to infinitely" many test cases for add() and you can't write them all down, but as this example shows, you should try to pick a "representative" set of tests. The big advantage of testing functions using assertions is that you don't have to "check" the output of a lot of println() instructions "by hand" anymore. Instead, you simply run the program with assertions enabled. If you see no output, that means you passed all the tests and gain confidence that your functions work as intended (although you can't be sure of course). If you see output, namely an AssertionError, that means something is still broken in your functions and needs fixing.

Finding "good" test cases is a pretty tough problem and lots of research has gone into that area. We'll just "skim the surface" here but as you may already know from your experience so far, testing is an important part of programming (although Dijkstra would disagree).

Deliverables

Submit your solutions by email to the submission address listed on the course website. Please make sure that you answer written questions in the text of the email. Please make sure that you attach programming questions as separate somename.java files. Note that you'll get a confusing automatic reply that I will explain later.

Finally, please include your name and email address as well as a brief comment explaining how to use your programs at the top of each Java file. Here's a template you can clone:

/*
 * CS 107
 * Assignment x: Problem y
 *
 * Your Name Here
 * Your Email Here
 *
 * Description of your program and any comments you may have
 * for the grader go here...
 */
Updated: $Id: assignment-3.html 112 2006-06-08 02:41:27Z phf $ Validate: XHTML CSS
Copyright © 2006 Peter H. Fröhlich. All rights reserved.