Make your own free website on Tripod.com
 

Discussion #4 - Programs and Global Variables


From now on, for simplicity, I shall refer to primitive procedures simply as "primitives" and to defined procedures simply as "procedures." Bear in mind, however, that "primitives" and "procedures" are really the same thing in the eye of the Interpreter. The only difference is in where they came from - primitives were invented by the people who wrote Logo and procedures are invented by you, the user of the language.

In Exploration #3 you experimented with procedures that had several instruction lines containing primitives and expressions. The Interpreter ran each procedure by executing the instruction lines in order from first to last. Within each line, the Interpreter executed the individual instructions in order from left to right. The Interpreter terminates its run when it reaches the procedure's END line. In this Unit, you will learn how to combine several procedures to make a program.

A program is a related set of procedures that call upon one another for help in solving a problem. The procedure that calls for help is identified as the superprocedure and the procedure that is called upon is identified as the subprocedure. When a super-procedure is the first procedure in a program - the one whose name is typed into the command center to start the program running - it is identified as the top-level procedure. One reason for using superprocedure-subprocedure pairs when writing a Logo program is to separate the preliminary steps from the actual operating steps. The names you give to each procedure in the pair should suggest this relationship.

In the example which follows, the superprocedure is named design and the subprocedure that it calls to actually draw the design is named do.design. Notice the use of the period in the subprocedure's name. You cannot use a space as part of a procedure's name, since the Interpreter assumes the space character signals the end of a program element. You want the Interpreter to consider the procedure's name as a single element, so you replace what would normally be a space in English with a period. In the program which follows, design is the top-level procedure. Its purpose is to ask you, the user, to provide input values that will determine the type of design to be drawn. When design has obtained the information it needs, it calls its subprocedure, do.design. do.design, in turn, calls its subprocedure, poly, to help it out with the drawing.

Here are the instructions that create the procedures used in this program. The three new primitives name, first, and rl are explained on pages 24 and 25.

TO DESIGN
  ct cg st pr [How many angles for each petal?]
  name first rl "angles pr [How big?]
  name first rl "size pr [How many petals?]
  name first rl "petals do.design ht
END
TO DO.DESIGN
  repeat :petals [poly rt 360 / :petals]
END
POLY
  repeat :angles [fd :size rt 360 / :angles]
END
To start the program running, you type design in the command center, because design is the top-level procedure of the program. The purpose of this procedure is to ask you, the user, for several input values and then to create variables to store these values for use by the commands in do.design and poly. Each pr instruction in design prints a description of one of the inputs (it "prompts" you for a value.) Each name instruction creates a variable to store the value for later retrieval. Variables that are created as part of a procedure by using the command name are called global variables. There is an important difference between the global variables that are created within a procedure by the primitive name, and the local variables you learned about in Unit #3. Local variables are variables that are named in the Title line of a procedure and given their values when that procedure is called. They exist in the workspace only while that procedure is being executed. Their scope is limited to the procedure in which they are named and any subprocedures of that procedure. Global variables are variables that are named and given their values when the primitive command name is executed. They exist in the workspace until removed by the command clearnames, Their scope is extended to all procedures which do not have a local variable with the same name.

In this program :ANGLES, :SIZE, and :PETALS are global variables because they were created by the primitive name in the design procedure. They are stored in the workspace and are available for use as inputs to commands in both of the subprocedures. There are no variable names in the Title lines of design, do.design, and poly because the variables used in this program are global rather than local variables.

The Interpreter's execution sequence is considerably more intricate when running a program than when running a single procedure. Whenever the Interpreter reaches an instruction that calls a subprocedure, it suspends its execution of the superprocedure and starts to execute the subprocedure instead. Upon completion of its execution of the subprocedure, the Interpreter resumes execution of the superprocedure at the point where it left off.

In the example above, the Interpreter suspends its execution of design when it reaches the do.design instruction and starts executing do.design instead. Similarly, it suspends its execution of do.design when it reaches the poly instruction. At that point, it executes poly, drawing the first petal of the design. When the Interpreter reaches the End line in poly, it returns to do.design and completes its evaluation of the quoted list, which rotates the turtle 360 / :PETALS degrees. The Interpreter then starts to evaluate the quoted list a second time, which again sends it to poly to draw a second petal before returning to do.design to complete the evaluation of the quoted list.

This back-and-forth maneuver between do.design and poly continues for :PETALS times, at which point the Interpreter goes on to the End line of do.design. Upon reaching the End line of do.design, the Interpreter returns to the top-level procedure, design, and picks up where it left off long before.

Many Logo programmers believe that global variables should be used very sparingly and that local variables should be used instead whenever possible. In long programs, there are practical reasons for this: global variables take up storage space from the moment they are created whereas local variables take up storage space only while their procedure is being executed. Moreover, it is sometimes confusing to identify the global variable input to a command in a subprocedure that is far removed from the procedure which created the variable, particularly if a local variable with the same name was created for another procedure in between. Most importantly, it is difficult to "export" for use in another program a subprocedure that depends upon global variables.

On the other hand, there are programmers who believe that top-level procedures should not have local variables, but rather should require the user to type only the procedure name and then be prompted for the inputs that will be needed later in the program. A compromise between these points of view is possible, as demonstrated in the design1 program below. A single prompt is printed, to which the user responds by typing in three numerals, each followed by pressing  < RETURN >. The Interpreter creates a local variable input for do.design1 following each  < RETURN > signal; when all three input variables have been created, the Interpreter proceeds to execute do.design1 with its three local variables. When do.design1 calls poly1 it passes on the values of two of these variables, in order to create poly1's local variables.
 
 

TO DESIGN1
  ct cg st
  pr [Enter the number of angles in each petal, the size of each petal, and the
     number of   petals in the design. Press the < RETURN > key after entering each number.]
  do.design1
  first rl
  first rl
  first rl
  ht
END

TO DO.DESIGN1 :ANGLES :SIZE :PETALS
  repeat :petals [poly1 :angles :size rt 360 / :petals]
END

TO POLY1 :ANGLES :SIZE
  repeat :angles [fd :size rt 360 / :angles]
END

 

Exploration #4

 

New Commands

name number, word, or list variable.name Creates a global variable with the second input as its name and the first input as its value.

shownames Displays the names and values of all the global variables in the workspace.

clearnames Deletes all the global variables in the workspace.
 

New Reporters

first list Outputs the first member of the input list. If the member is a numeral or a quoted list, first evaluates it by calculating the decimal value or removing the brackets before outputting.

readlist (rl) Suspends execution of an instruction in order to receive an input list from the keyboard. When the key is pressed, readlist outputs this list. first and rl are used together in the name instruction because you wish the Interpreter to assign a number, not a list, as the value of the variable. The reporter rl outputs to first a one-member list containing the numeral you typed, and the reporter first removes this numeral from the list. evaluates it, and outputs the resulting number to name. You might like to define a new reporter, rw (readword), which combines these two primitive reporters and outputs a word directly.

TO RW
  op
  first
  rl
END


By adding rw to the Tools page, your startup procedure will automatically add this command to the workspace of your computer, along with the color names you added earlier. You can then use rw whenever you wish, just as if it were a primitive. For convenience, I shall use the defined reporter rw instead of the primitive reporters first rl in the rest of the units of this text.
 

New Command or Reporter

run instruction, instruction.list or expression If the input is an instruction or instruction list, run acts as a command which produces the same effect as repeat 1; that is, run simply executes its input. If the input is an expression, run acts as a reporter; run evaluates its input and outputs a value.

1. Type design and its subprocedures on the flip side of a new page of your scrapbook. Return to the front side and experiment with it, using many different inputs to see what designs you can create. As the program runs, try to imagine what the Interpreter is doing to create each design.

2. Type design1 and its subprocedures on the flip side of the same page. Experiment with it, using a variety of inputs. Even though the variables used in design and design1 have the same names the Interpreter is not confused, since design's variables are global and design1's variables are local.

3. After defining the DESIGN and DESIGN1 programs, type do.design in the command center, and then type do.design1 there. Do you understand the Interpreter's differing responses to these two procedure calls?

4. Create another version of design, called design2, which includes a fourth input value, a :COLOR variable. Add a new prompt and a new name instruction in design2 to create this variable, and a new setc instruction in poly2 to use it. If you choose to enter the color as a defined reporter, such as red instead of as a color number from the Colors page (assuming you have stored red in the workspace of your computer as a tool procedure) you will need to include the reporter run as part of the name instruction line in design2. name run rw "color run evaluates the defined color reporter that you type in response to the input prompt, and passes its output number as the value for name to use in creating the variable :COLOR. If you did not include run, the word "red (the result of evaluating rw) would be assigned as the value of :COLOR rather than the number 5 (the result of evaluating the reporter red). This difference is important, since setc needs to have a number, not a word, as its input. If you chose to enter the color as a number rather than as a defined reporter such as red, you would not need to include run, since the Interpreter would evaluate rw as the number you entered and pass it directly to name. However, since run also accepts a number as an input and passes the number along as its output, it is a good idea to include run as part of the instruction so that the user has a choice of responding to the prompt by typing either a color name or a color numeral. As you see from the description above, run is a very unusual primitive. Depending upon its input, it can serve either as a command or as a reporter. In this case, run is a reporter. The Interpreter evaluates the expression passed to run by rw (the name of a defined procedure such as red or a numeral such as 5) and passes the result to name. name assigns this input (the number 5 in either case above) as the value of the variable :COLOR.

5. Elaborate on the design a bit by adding a small forward movement as well as a turn between each repetition of poly. This should be added as part of the quoted list in do.design. If you like this effect, you might consider adding another variable to design to specify how much forward movement you desire.

6. Could you modify poly to include a fill instruction for each petal?

7. Could you modify poly to make the petals in the shape of stars instead of polygons?