Spider | Previous | Next | Full Table of Contents | Index | Program List | Copyright

6.8 Continuing Saga: A Child Package for the Spider

Let's pay another visit to the spider. You've seen so far how to command the spider to move around and draw shapes on the screen. Now that you know how to write procedures, let's consider how to add our own commands to the set of commands the spider can obey. Look again at the specification, Program 3.11. Specifically, we note the absence of two useful commands:

Suppose we were just writing a spider program. How could we get the effect of the Left command? There are several ways, as we show in these code fragments. First, we can turn left by turning right:

    Spider.Right;
    Spider.Right;
    Spider.Right;
 

This works, but it is not very realistic--would you turn left that way? Another approach is to ask which direction the spider is facing and then tell it to face in another direction:

    IF Spider.IsFacing = North THEN
      Spider.Face(WhichWay => West);
    ELSIF Spider.IsFacing = East THEN
      Spider.Face(WhichWay => North);
    ELSIF Spider.IsFacing = South THEN
      Spider.Face(WhichWay => East);
    ELSE -- Spider must be facing West
      Spider.Face(WhichWay => South);
    END IF;
 

This will work, but we have to be very careful in writing it that all the directions are covered and that the Face command has the right parameter. We note that Spider.Directions is an enumeration type,

    TYPE Directions IS (North, East, South, West);
 

and that a left turn can be implemented very easily as the predecessor of the current direction. We've seen a similar problem before, in Program 4.4, where given a representation of today, we needed to find yesterday and tomorrow. We must be a bit careful in taking the predecessor: If the current direction is North, just taking the predecessor will fail on Constraint_Error because the enumeration doesn't "wrap around." The statement we need is, in fact,

    IF Spider.IsFacing = Spider.North THEN
      Spider.Face(Spider.West);
    ELSE
      Spider.Face(Spider.Directions'Pred(Spider.IsFacing));
    END IF;
 

or, to write it in more general terms (in case some day the directions are given in French),

    IF Spider.IsFacing = Spider.Directions'First THEN
      Spider.Face(Spider.Directions'Last);
    ELSE
      Spider.Face(Spider.Directions'Pred(Spider.IsFacing));
    END IF;
 

Implementing the new Step is much easier: it's just a counting loop with Spider.Step as the loop body.

Putting the New Commands in a Child Package

It is now time to implement the new commands as a set of procedures. Because these are commonly used commands, it is best to put them in a package. Since this new package is not just using the original spider package but is, in fact, closely related to it, we can define this relationship in an Ada child package.

We have seen child packages before; indeed, all the standard packages we've used are children of Ada.[1] The specification for our child package, Spider.My_Stuff, appears as Program 6.13 and just codes the procedure specifications we've discussed here.

Program 6.13
Specification for Child Package Spider.My_Stuff

PACKAGE Spider.My_Stuff IS
------------------------------------------------------------------------
--| Additional Spider Commands; this is a child package.
--| Author: Michael B. Feldman, The George Washington University 
--| Last Modified: July 1995                                     
------------------------------------------------------------------------
 
  PROCEDURE Left;
  -- Pre:  None
  -- Post: Spider turns 90 degrees to the left. 
 
  PROCEDURE Step(HowMany: IN Positive);
  -- Pre:  None
  -- Post: Spider takes HowMany steps forward 
  --   in the direction it is facing.
  -- Raises: Hit_the_Wall is if spider tries to step into a wall.
 
END Spider.My_Stuff;
 

The body of Spider.My_Stuff appears as Program 6.14. The procedure bodies incorporate the statements we just discussed; note, however, that no qualifications are necessary on the various calls. That is, we can write IsFacing instead of Spider.IsFacing, and so on. This tells us that the body of the child package can automatically "see" everything in its parent's package specification (it cannot see into its parent's package body, though).

Program 6.14
Body of Child Package Spider.My_Stuff

PACKAGE BODY Spider.My_Stuff IS
------------------------------------------------------------------------
--| Child Package Body for Additional Spider Commands
--| Author: Michael B. Feldman, The George Washington University 
--| Last Modified: July 1995                                     
------------------------------------------------------------------------
 
  PROCEDURE Left IS
  BEGIN
    IF IsFacing = Directions'First THEN
      Face(Directions'Last);
    ELSE
      Face(Directions'Pred(IsFacing));
    END IF;
  END Left;
 
  PROCEDURE Step(HowMany: IN Positive) IS
  BEGIN
    FOR Count IN 1..HowMany LOOP
      Step;
    END LOOP;
  END Step;
 
END Spider.My_Stuff;
 

SYNTAX DISPLAY
Child Package

Syntactically, a child package is exactly like any other, except for its name, which is of the form Parent.Child. The parent package must exist already to permit compilation of the child package. Under normal circumstances, one is not permitted to compile new children of the package Ada since this parent package is reserved for standard (language-defined) packages.

Writing Applications of the Spider Packages, Parent and Child

Program 6.15 shows how to use the packages Spider and Spider.My_Stuff. Note that because this program uses both packages, it must have context clauses (WITHs) for both. The spider draws a box, turning left at the corners instead of right. This program is simpler than Program 5.11 because we can take advantage of the multiple-step command in the child package. We omit the sample run because it is very similar to the output of the box programs of Section 5.5.

Program 6.15
The Spider Draws a Counterclockwise Box

WITH Spider;
WITH Spider.My_Stuff;
PROCEDURE Draw_Box_with_Loops_Left IS
------------------------------------------------------------------------
--| Draw 4 x 4 box with spider - use nested loops and turn left
--| Author: Michael B. Feldman, The George Washington University
--| Last Modified: July 1995
------------------------------------------------------------------------
 
BEGIN -- Draw_Box_with_Loops_Left
 
  Spider.Start;
 
  FOR Side IN 1..4 LOOP
    Spider.My_Stuff.Step(HowMany => 5);
    Spider.My_Stuff.Left;
  END LOOP;
 
  Spider.Quit;
 
END Draw_Box_with_Loops_Left;
 

Finally, in Program 6.16 we show a program that commands the spider to move from its starting position in the center of its room to the wall, then inspect the edges of the room, turning left at the corners. This program uses WHILE loops to get the spider to turn before it steps into the wall. One WHILE loop gets the spider to the first wall, then another WHILE loop is nested inside the FOR loop that counts the walls.

Note in the sample run that the spider does not quite get back to where it started and that it leaves half of one wall uninspected. We leave correcting this as an exercise.

Program 6.16
The Spider Tours the Edges of Its Room

WITH Spider;
WITH Spider.My_Stuff;
PROCEDURE Tour_Room IS
------------------------------------------------------------------------
--| Spider takes a tour around the edges of its room.
--| Author: Michael B. Feldman, The George Washington University
--| Last Modified: July 1995
------------------------------------------------------------------------
 
BEGIN -- Tour_Room
 
  Spider.Start;
 
  -- first get to a wall
  WHILE NOT Spider.AtWall LOOP
    Spider.Step;
  END LOOP;
 
  -- now turn and tour the four walls
  FOR Wall IN 1..4 LOOP
    Spider.My_Stuff.Left;
    
    -- walk the length of this wall
    WHILE NOT Spider.AtWall LOOP
      Spider.Step;
    END LOOP;
  END LOOP;
 
  Spider.Quit;
 
END Tour_Room;
 

Sample Run

                    ----------------------------------------- 
 ---               |O O O O O O O O O O O . . . . . . . . . *|
| ^ |              |O . . . . . . . . . O . . . . . . . . . O|
| O |              |O . . . . . . . . . O . . . . . . . . . O|
 ---               |O . . . . . . . . . O . . . . . . . . . O|
                   |O . . . . . . . . . O . . . . . . . . . O|
                   |O . . . . . . . . . O . . . . . . . . . O|
                   |O . . . . . . . . . O . . . . . . . . . O|
                   |O . . . . . . . . . O . . . . . . . . . O|
                   |O . . . . . . . . . O . . . . . . . . . O|
                   |O . . . . . . . . . O . . . . . . . . . O|
                   |O . . . . . . . . . O . . . . . . . . . O|
                   |O . . . . . . . . . . . . . . . . . . . O|
                   |O . . . . . . . . . . . . . . . . . . . O|
                   |O . . . . . . . . . . . . . . . . . . . O|
                   |O . . . . . . . . . . . . . . . . . . . O|
                   |O . . . . . . . . . . . . . . . . . . . O|
                   |O . . . . . . . . . . . . . . . . . . . O|
                   |O . . . . . . . . . . . . . . . . . . . O|
                   |O . . . . . . . . . . . . . . . . . . . O|
                   |O . . . . . . . . . . . . . . . . . . . O|
                   |O O O O O O O O O O O O O O O O O O O O O|
                    ----------------------------------------- 
 


[1] Child packages are new to Ada 95. In Ada 83, we would either just write a normal package that WITH-ed Spider, or modified the original spider package by adding the new commands.
Spider | Previous | Next | Full Table of Contents | Index | Program List | Copyright

Copyright ©1996 by Addison-Wesley Publishing Company, Inc.