CSC 115.005/006 Sonoma State University Spring 2022
Scribbler 2
CSC 115.005/006:
Programming I
Scribbler 2
Instructor: Henry M. Walker

Lecturer, Sonoma State University
Professor Emeritus of Computer Science and Mathematics, Grinnell College


Course Home References Course Details: Syllabus, Schedule, Deadlines, Topic organization MyroC Documentation Project Scope/
Acknowledgments

Notes:

An Introduction to Program Organization

At this point in the course, laboratory exercises have involved writing short programs to solve some simple problems. As you would expect, future tasks will involve larger and more complex problems. In anticipation of this later work, we need to develop strategies and practices that can help us to be effective and efficient in writing correct solutions to these problems.

Throughout the course, we will methodically expand our problem-solving insights and techniques. In this reading, we begin with three principles:

This reading introduces each of these principles.

Some Definitions

When a solution to a problem might include the same code in several places, a mechanism is needed to extract the details into a common place and then referenced as needed. In C, the mechanism to collect this common material is called a function or procedure.

When details of a solution are collected in one place (e.g., a function or procedure) and used in several places, details are separated from their use. This is procedural abstraction; one part of the code serves as a high-level outline of the steps of an algorithm using function/procedure references, while the low-level details of those steps are given elsewhere and do not mask the overall flow of the solution.

When code is first written, it must be tested. When errors are identified (i.e., when the answers produced are not correct to solve the problem), the error must be resolved. The process of finding and correcting errors is called debugging.


Write code once, not multiple times

Although the principle, "write code once, not multiple times", may seem straightforward and obvious, applying this principle may require some planning and insight. To illustrate this point, consider the myroc-espeak-1.c program from the reading on Using the Scribbler 2.

You may recall that the program header identified three main parts of the program:

/* Program combining test-to-speech capabilities
 * with Scribbler 2 motion and sound
 *
 * Part 1: robot moves forward and right three times 
 *         while playing an ascending musical chord 
 * Part 2: robot moves forward and left three times 
 *         while playing a descending musical chord
 * Part 3: repeats Part 1
 *
 * Author:  Henry M. Walker
 * Date created:  12 May 2016
 * 
 */

Although the code worked without difficulty, at least four criticisms are possible.


The names used for the pitches in myroc-espeak-1.c come from common labeling of keys on a piano.



Header Files

With these weaknesses identified for myroc-espeak-1.c, we consider how to construct a better version, myroc-espeak-2.c

To begin, we create a new program, scale-notes.h, that contains C code to define the 88 notes on a piano. Rather than focus on just the four notes needed for this specific program, scale-notes.h defines the full range of pitches on the Western well-tempered scale. In any particular program, we may not need all of these pitches defined. However, by having all pitches available, we can choose what we need; if we decide to expand the program later, the full range of pitches will already be available.

Once defined, we should place the file scale-notes.h in the directory with our other programs. Then we can reference it with an include statement, in much the same way we identify standard libraries.

When using an include statement

Notes for include

Operationally, when a C compiler encounters an include statement, the compiler inserts the text of the file into the current program. Thus, if a compiler were working with myroc-espeak-2.c and encountered include "scale-notes.h", the compiler would locate this new file and read in line-by-line into myroc-espeak-2.c. One might consider include as a directive to copy-and-paste additional text into a file.


Functions and procedures

To address the challenge of duplicate code, we proceed in 3 steps:


As an example, consider myroc-espeak-1.c as the base for the revised program myroc-espeak-2.c

We will use the name forward_right to describe the common block of code for Parts 1 and 3. Within C the beginning of this block of code follows a specific format that also describes what the code will do:

/*
  Procedure to move the robot forward
     and right three times while playing
     an ascending musical chord
 */
void forward_right ()

Following this header, the desired block of code is placed in braces. The full procedure follows:

/*
  Procedure to move the robot forward
     and right three times while playing
     an ascending musical chord
 */
void forward_right ()
{
  eSpeakTalk ("move forward and turn right");
  rForward (1.0, 1.0);
  rBeep (0.5, pitchC6);
  rTurnRight (0.7, 0.75);
  
  eSpeakTalk ("move forward and turn right again");
  rForward (1.0, 1.0);
  rBeep (0.5, pitchE6);
  rTurnRight (0.7, 0.5);
  
  eSpeakTalk ("move and turn a third time");
  rForward (1.0, 1.0);
  rBeep (0.5, pitchG6);
  rTurnRight (0.7, 0.25);

  rBeep (0.5, pitchC7);
}

Notes on procedure forward_right


Similarly for myroc-espeak-2.c, we could define a procedure forward_left for Part 2. Although this code is only used once, definition of a procedure would highlight the separate nature of those details.


With forward_right and forward_left defined, the main procedure highlights the main flow of the overall program:

int main ()
{
  // connect for both MyroC and eSpeak
  rConnect ("/dev/rfcomm0");
  eSpeakConnect ();

  /* Part 1: robot moves forward and right three times 
             while playing an ascending musical chord 
  */
  printf ("starting Part 1\n");
  forward_right ();
  
  /* Part 2: robot moves forward and left three times 
             while playing a descending musical chord 
  */
  eSpeakSetGender ("female");  // specify voice characteristics
  printf ("starting Part 2\n");
  forward_left ();

  /* Part 3: robot moves forward and right three times 
             while playing an ascending musical chord 
  */
  eSpeakSetGender ("male");  // specify voice characteristics
  printf ("starting Part 3\n");
  eSpeakTalk ("Part 3 repeats Part 1");
  forward_right ();

  // finish with no errors
  eSpeakTalk ("Enough of this; I am going to stop now");
  rDisconnect ();
  eSpeakDisconnect ();

  return 0;
}

The complete, revised program, with needed include statements, is available as myroc-espeak-2.c.


Comments

The very first reading on C programming emphasized that "Since a program articulates a proposed algorithm to accomplish a desired task, the program should be considered as a formal mechanism for precise communication. As a communication vehicle, a program has at least three audiences:" the author, other people, and computers. C's specific syntax and semantics allows computers to compile and run programs — largely handling communication to computers.

Comments and formatting can make a substantial difference in communication to the programming and to others.

Although comments can help others understand a program after it is written, comments can be particularly helpful to authors as they are writing the code.


Altogether, programmers are urged to write comments early!.

Words of common wisdom


Write code incrementally, not all at once

Once an overall program is organized into pieces (e.g., with procedures), an author often can write many elements of main. In getting started,

With this arrangement, the program represents the proper overall structure of a solution, but few details are completed.

Stubs

A stub is a small block of code that identifies a logical step to be performed, but which has limited initial functionality.

For example, when starting to write the myroc-espeak-2.c program, the forward_right and forward_left procedures might be simple stub:

void forward_right ()
{
   printf ("procedure forward_right not yet implement\n");
}

void forward_left ()
{
   printf ("procedure forward_left not yet implement\n");
}

With stubs for procedures, the overall program, as given above in the reading, can run using the proper structure, and the printf statements print text that checks the flow of operations.

The code may not do much when development of a program begins, but the main pieces are in place.


With this structure in place, a programmer can focus on one piece of the overall code at a time. No need to write all details at once and then have to contend with possible issues in dozens or hundreds of lines of code!

By writing one piece of code at a time, a programmer can focus on a few lines, in writing, compiling and running the program.

In developing large programs, an important challenge is to manage complexity. If a complex solution can be divided into small tasks, then work can proceed methodically step-by-step, and a programmer does not have to keep many details and logical connections in mind all at once.