Lab 7: Aesthetics and the World

As usual, you will


Program Aesthetics

... a computer language is not just a way of getting a computer to perform operations but rather that it is a novel formal medium for expressing ideas about methodology. Thus, programs must be written for people to read, and only incidentally for machines to execute. - SICP
Where there is mystery, it is generally suspected there must also be evil. - Lord Byron

Programs are written to be read by other programmers. Other programmers may want to modify or extend your program, to fix a defect in your program, or simply to understand how your program works. In particular, your graders are programmers whose job is to determine if your program meets its specification. Therefore, you must make your programs readable.

This course equips you with two techniques for producing readable programs: the first is to follow the design recipe, and the second is to properly format well-designed code. We will cover three guidelines for proper code format.

The homework server may reject submissions that do not follow these guidelines!

Guideline 1: Break Lines

Recall the data definition for Time:

(define-struct time (hours minutes))
;; A Time is (make-time Number Number)
Consider this program:
;; Time -> Image
;; Produce an image of the given time, as it appears on a digital clock.
(define (time->text a-time)
  (text (string-append (number->string (time-hours a-time)) ":" (cond [(< (time-minutes a-time) 10) "0"]
  [else ""]) (number->string (time-minutes a-time))) 30 'red))
  1. How many arguments are there to text?
  2. How many cond clauses are there?
  3. What are the arguments to string-append?
This code is a disaster. Because the body is squeezed onto two lines, we cannot answer these questions at a glance. If we insert line breaks, the code becomes
;; Time -> Image
;; Produce an image of the given time, as it appears on a digital clock.
(define (time->text a-time)
  (text (string-append (number->string (time-hours a-time))
                       ":"
                       (cond 
                         [(< (time-minutes a-time) 10) "0"]
                         [else ""])
                       (number->string (time-minutes a-time)))
        30
        'red)
With this code, it is easy to see the three arguments to text , the four strings being appended, and the two cond clauses.

In general, try to break long lines by

If these formatting hints do not help, consider designing and using a helper function to make the code less verbose. For example, in time->text above, it's probably a good idea to "factor out" the (string-append ..) expression as a separate helper function.

Every line of code should be no more than 80 characters long. The homework server will reject submissions when they contain a line with more than 80 characters.

Exercise: Rewrite time->text by developing and using a helper function that computes the (string-append ...) portion of the body. Be sure to invent a good name for this helper function.

Guideline 2: Indentatation

Recall this program from last lab:

;; LOS -> Number
;; Determine how many symbols are in a-los
(define (count a-los)
  (cond
[(empty? a-los) 0]
 [(cons? a-los)
  (+ 1 (count (rest a-los)))]))
What's wrong here? The code is not "lined up" properly. That is to say, it is not indented properly. Copy and paste this code into DrScheme. Then, in DrScheme, select Reindent All under the Scheme menu. DrScheme will indent the code properly automatically! Make good use of this feature as you develop your programs. Also note that the tab key can be used to automatically indent just the line that the cursor is on.

When you use the Reindent All feature or the tab key, your code might appear differently than you expect. This usually means that your program is mis-parenthesized. Move the cursor through your code and use the grey highlighting to be sure that your parentheses are matched as you intend.

Guideline 3: Parentheses Layout

Let's reconsider count from above. The indentation is technically correct, but the parentheses are arranged a bit differently:

;; LOS -> Number
;; Determine how many symbols are in a-los
(define (count a-los)
  (cond
    [(empty? a-los) 0
    ]
    [(cons? a-los)
     (+ 1 (count (rest a-los))
     )
    ]
   )
)
A programmer who arranges their parentheses like this is probably trying to use the vertical alignment of the open and closing parentheses to visually determine the code structure. It is much easier to compress the closing parentheses together, and then eyeball the program structure using its indentation. When you need to match parentheses visually, use DrScheme's grey highlighting instead.
;; LOS -> Number
;; Determine how many symbols are in a-los
(define (count a-los)
  (cond
    [(empty? a-los) 0]
    [(cons? a-los)
     (+ 1 (count (rest a-los)))]))
Proper indentation and parentheses placement render the parentheses and brackets nearly invisible to the trained eye. The indentation should always clearly indicate the program structure.

On your own time: Look at Part 1 of last year's Lab 9 for a richer set of examples and guidelines. Note that some examples in that lab uses a construct called local that we have not yet covered. Skip those examples for the time being.


DrScheme: The Operating System of Choice for Beginning Hackers

An operating system (OS) is a program that listens to and reacts to the "environment" all the time. When anything of interest happens, the OS takes some action or may ask another program to react by calling it on some input. These "things of interest" are called events, and when the OS calls another program, it passes in some information about the relevant event. Programs that we write for the OS to use to respond to events are typically referred to as event handlers. Note that the OS will not use our programs as event handlers by default. We must explicitly instruct the OS to do so. The process of telling the OS to use our program as an event handler is referred to as registering an event handler.

For Beginning Student Language programmers like us, the operating system is DrScheme. DrScheme listens to clock ticks, keystrokes, and mouse movements and clicks. Each of these actions causes events to which the OS may react.

  1. Clock ticks are events.
  2. A keystroke generates two separate events: the key press and the key release. Events caused by a keystroke are called KeyEvents, and the Help Desk documentation for on-key-event contains a data definition for KeyEvent.
  3. There are several kinds of mouse events because we use the mouse in various ways. For example, we may click, drag, move the mouse into a window, or move the mouse out of a window. Look at the documentation for on-mouse-event for a data definition describing mouse events.
You should also know that the OS reacts to events in a sequential manner. It may appear to react to clock ticks and key events simultaneously, but what really happens is that the OS processes one first and then the other. The computer just does this so quickly that it appears to us as though the events are handled at the same time.

Finally, the OS does one more useful thing: it keeps track of information that might change from event to event. We typically refer to this information that may change as "the state" or "the world" or even "the state of the world." In our programs, we typically represent the world as an instance of some structure that contains several pieces of data (such as the position and velocity of a rocket). When the OS reacts to an event by calling a program, it also passes in the world to that program. When that program produces a new world, the OS will hang onto it and use it to handle subsequent events.

With all these interesting things happening, it sure would be nice to see the results of the computer's labor. On top of all of the event handling, the OS gives us a way to view the progress of the computation at any point in time. We can write a function that interprets the data in the world and produces, say, an image. We can then ask the OS to call our function every time the world changes, and the OS will draw the result into a window so that we can see it. If we arrange for the world to change several times per second (using the clock tick events), then we can create an animation or a movie.

To write animations and interactive programs like the rocket launch, the UFO game, or the Worm game, we just need to write programs that react to clock ticks, keystrokes, and the mouse. We then register our programs as event handlers. We also tell the OS how often we want the clock to tick, what the initial world is, and how big the drawing window is. The OS provides several built-in functions that enable us to register our event handlers:

Search Help Desk for world.ss to see formal contracts and purpose statements for each of these functions.

Example

We provide a small program that draws a single circle in the window. When the mouse is clicked, the circle moves to the location of the mouse click. The circle is also dragged in response to the mouse being dragged while the button is down.

The left and right arrow keys will move the circle left and right.

As the time ticks away the radius of the circle shrinks until it decreases to 5, where it then stays.

Download the program here: my-world.ss.

Exercise

Use the rest of the lab time to work on your homework assignment. Remember, the tutors are right there: take advantage of this time to ask them questions.


Last modified: Mon Oct 16 19:26:11 EDT 2006