BFOIT

Introduction to Programming

    Defining Your Own Commands    


Introduction

For getting the turtle to draw simple things, like a triangle or a square, you can just enter TurtleTalk commands and most of the time your program just works - it does what you thought it would.  However, as the programs you want to write get bigger, you will certainly run into problems.  The more TurtleTalk commands you include in your programs, the more you need to type into the computer, the more chance you have for mistakes.

In this lesson you will learn how to add your own new commands to the TurtleTalk language.  You will teach the TurtleTalk interpreter how to do some new things.  This capability to name procedures that are made up of other already existing TurtleTalk stuff is called abstraction; and, as you are about to learn, is a big help in constructing good programs.


How To Write Large TurtleTalk Programs
That Do What You Want

When you did the Exercises at the end of the last lesson, my guess is that you didn't type in programs that worked perfectly the first time.  If you did, congratulations... you are great at visualization and orderly thought.  The good news is that anyone can learn to write correct programs - an experienced programmer would have no problem writing "correct" programs for these exercises. 

Why?

As you are about to learn, an experienced programmer would think about how to solve the problem before she would start entering TurtleTalk commands.  An experienced programmer would break the problem into pieces that each are simple to do by themselves.  Then, put all the pieces together to solve the problem.

Let's play "experienced programmer" with the first exercise.


Understanding the Problem

What you should do first is think about what you need to do.  Get out some paper and a pencil to write down your thoughts.  Look at the diagram carefully.  How can you break it up into multiple, simpler to do parts.

You need to get the turtle to:

This completes the "Understanding the Problem" phase. 

The next phase is "Devising a Plan" - how do you get the turtle to draw the things you've identified.


Devising a Plan

So you now have some notes on your piece of paper that describe ways that lead to a solution.  The next step is to decide on an approach and put together a process which gets the turtle to draw the figure.

Let's follow our experienced programmer's thoughts through the rest of a solution.  She has chosen to draw a square (a special kind of rectangle) and subdivide it.  So, she needs to figure out how many turtle steps each side of the square needs to be.  Since it will be split in half and into thirds, she needs a length that is a multiple of 2 and 3.  She likes nice round numbers so she makes each side of the square 120 turtle steps (120/2=60; 120/3=40).  As you can see, it's nice to know a little bit of math when you're programming.

With this decided, she first writes her program down on a paper in pseudo-code.

   1. draw a square
   2. draw the vertical line that splits the square in half
   3. draw the top horizontal line spliting the right half
   4. draw the bottom horizontal line spliting the right half
   5. make the turtle invisible
Pseudo-code is a term for describing something in your native language.  Her pseudo-code is English descriptions of what she wants her program to do.  Once this is complete and she is convinced that her plan should produce what she wants, it's time for the next phase: converting the pseudo-code into TurtleTalk commands.


Carrying Out the Plan

Time to convert the plan into a program that can be executed on a computer.  Since she is programming in TurtleTalk, our expert programmer will convert the pseudo-code into instructions available in this computer language.  Table 3.1 shows the both the pseudo-code and the results of its conversion to TurtleTalk.

 
Pseudo-code
(Written on Paper)
TurtleTalk Instructions
(Typed on Computer)
 draw a square  fd 120 rt 90 fd 120 rt 90 fd 120 rt 90 fd 120 
 draw the vertical line that splits the square in half   bk 60 rt 90 fd 120 
 draw the top horizontal line spliting the right half   bk 40 rt 90 fd 60 bk 60 lt 90 
 draw the bottom horizontal line spliting the right half   bk 40 rt 90 fd 60 
 make the turtle invisible   ht 
Table 3.1

Our experienced programmer starts the TurtleTalk interpreter on her computer.  She reads her pseudo-code notes (converting them to TurtleTalk commands in her head) and types in the code.  As each line is [Enter]-ed she watches the turtle do exactly what's expected.


Exercise: Draw a House

Try this approach to programming just described.  Write a program that draws a simple house.  Go through all of the steps I've talked about:

  1. Understanding the Problem,
  2. Devising a Plan, and
  3. Carrying out the Plan.

 Although it's not the
 most attractive house,
 it is easy to draw
 with the turtle.
 

 Make the front of the
 house a square with
 each side 100 turtle
 steps.


 Make the roof an
 equilateral triangle,
 with each side 100
 turtle steps.


 Make the door 50
 turtle steps high
 and 25 turtle steps
 wide.


 Make the window a
 square, 25 turtle
 steps on each side.
      
Figure 3.1

First, get out a piece of paper and draw two columns on it.  Start in the left column; write down the big steps you would go through to draw the house.  Leave room between the steps.  When your done, move to the right column and write the TurtleTalk instructions needed to actually accomplish each step.

After you have you program written on paper, here is the TG applet for you to use.  Type the instructions you've written down into the TurtleTalk interpreter.  Does it do what you thought it would?

alt="Your browser understands the <APPLET> tag but isn't running the applet, for some reason." Your browser is completely ignoring the <APPLET> tag!
TurtleGraphics Applet


Defining Your Own Commands - Procedural Abstraction

You've now learned how to break your programs into pieces; each piece is easy to understand by itself.  Your program is the concatenation of the pieces.  This approach is very important for writing programs that do what you want them to.  This is the way I was taught to program. 

But, my interaction with a computer consisted of getting a little bit of time on a computer I shared with hundreds of others.  So, use of paper and a pencil for the first steps was important.  But now everyone has their own computer...  Let's take advantage of this and eliminate the use of paper and pencil.

We're not going to change the steps in the programming process:

  1. writing pseudo-code,
  2. converting it to TurtleTalk instructions, and
  3. typing your TurtleTalk program into the interpreter.

Instead, there's a way to replace the notes and pseudo-code on paper with stuff we type into the TurtleTalk interpreter.  We will use comments embedded in our TurtleTalk instructions and a technique called procedural abstraction.  For now, you can think of procedural abstraction as the ability for you to invent your own new TurtleTalk commands.  Each of your new commands will do something simple.  Your computer programs then become lists of your new commands. 

Procedural abstraction is the most important programming concept you will learn!

Let's work through an example.  It will give you a good feel for what I'm attempting to describe.

Pseudo-code TurtleTalk Instructions
  draw a box  
  with sides  
  = 100 steps  
  fd 100 rt 90 fd 100 rt 90 fd 100 rt 90 fd 100 rt 90  
Table 3.2

By now you have to be good at drawing a square box.  Table 3.2 shows a pseudo-code description of what to do and its comparable list of TurtleTalk instructions. 

Here are a few problems I have with the list of instructions.

  1. without the pseudo-code, it takes a non-trivial amount of thinking to figure out what the list of instructions does,
  2. if it is in the middle of other instructions it is even harder to figure out what the combination of instructions does,
  3. it takes a lot of time to type every time you want a square box that's 100 steps on a side, and
  4. it consists of so many characters that it is easy to make a typing error.

What we need is the ability to give a name (also known as an identifier) to the list of instructions that draw this square box.  And, we need to make the TurtleTalk interpreter aware of this name and treat it just like the built-in commands it already has. 

We can do this.  The TurtleTalk interpreter allows you to create your own commands.  Here's how...

To define a new command that draws a box, 100 steps on a side, you type:

   to box100
     fd 100 rt 90
     fd 100 rt 90
     fd 100 rt 90
     fd 100 rt 90
     end
into the interpreter.  You could also type:
   to box100
     fd 100 rt 90 fd 100 rt 90 fd 100 rt 90 fd 100 rt 90
     end
I prefer the first version because it is easier to read and with the symmetry of the four lines, it's easier to see that it is correct.

So, what have we done here? 

We've used a very special command ("to") to teach the TurtleTalk interpreter a new command.  Just as it understands "forward" and "right" commands, it now understands what a "box100" command is and does.  We've defined a new command, also known as a new procedure.  Since a command is one kind of a procedure (there are others), from this point on I'm going to use the term procedure definition in place of command definition.

What does this special "to" command look like?

The general form, the syntax, of a "to" command, a procedure definition is:

   to       <name>   
     <TurtleTalk-Instructions>   
   ...   
   end   

Procedure definitions consist of:

  1. a title line (the "to" line containing the procedure's name, its identifier),
  2. a body consisting of one or more lines of instructions, and
  3. an end line (the word "end")

Once you've defined box100 you can use it like any of the TurtleTalk commands you've been using.  You've just taught the TurtleTalk interpreter how to do something; you've added a command to TurtleTalk's vocabulary.

Either go back up to the TG applet or use a small popup TG applet to type in the definition of box100.  Try using it to draw a couple of boxes at different locations in TurtleSpace.

Then, try typing:


   box100 rt 45
a few times...  What does this do?  cool, huh?


Procedure Definition vs Procedure Invocation

When you typed in the definition of box100, did anything surprise you?  Did you notice that defining your own command (a procedure) causes the TurtleGraphics applet to behave differently?

Up till now, every time you typed TurtleTalk commands and pressed the "Enter" key, something happened to the turtle in the graphics area of the applet.  But, when you typed in "to box100" and then pushed the "Enter" key, nothing happened in TurtleSpace.  Instead, the CommandCenter name stripe changed:

"Defining Procedure: box100"
appeared to the left of the word "CommandCenter" and the cursor moved to the next line, positioned to the right of a new/different prompt.  The characters "> " are to the left of the prompt instead of the "? " characters you've been seeing.  Finally, the cursor is automatically indented a couple of spaces. 

When you continued typing, adding TurtleTalk commands, e.g., "fd 100 rt 90" and hit the "Enter" key, again, nothing happened in the graphics area.  But, the "> " characters remained the prompt and the cursor was still indented a couple of spaces on each new line. 

Although it is not obvious, the TurtleTalk interpreter is doing something - it's checking to make sure that what you are typing is legal TurtleTalk.  If it is, what you are typing is just collected, stored away someplace, remembered for later use.  You are teaching the interpreter how to do something new and it is remembering what you are typing.

Finally, when you typed in "end" and the "Enter" key, (called the end line) the phrase "Defining&nbps;Procedure:&nbps;box100" disappeared in the stripe above the terminal area, the prompt characters went back to "? " and the cursor was no longer indented a couple of spaces.  You've completed the definition of the new command.  All of the stuff that changed - the stripe above the terminal, the prompt, the extra indentation - were feedback to you from the TurtleTalk interpreter, to make sure you knew that you were in the process of defining a command.

Once you have completed defining your new command, you can then use it.  When you type its name ("box100"), the TurtleTalk interpreter recognizes it and does what you told it to do when you defined it.  Typing its name to get the interpreter to perform it is technically called invoking it, a.k.a. calling it, doing it, performing it, ...

In summary, defining a procedure is teaching the interpreter how to do something, typing the procedure's name into the interpreter is invoking it - asking the interpreter to do what you taught it.


TurtleTalk Animation

Here is a small TurtleTalk program consisting of two procedure definitions (main and box100) and one invocation of main and four invocations of box100.  Watch how the program is executed, step by step.

alt="Your browser understands the <APPLET> tag but isn't running the applet, for some reason." Your browser is completely ignoring the <APPLET> tag!


Eliminating Paper and Pencil with Procedural Abstraction

Now that you know how to define new TurtleTalk procedures, I'm going to show you how you can use them to eliminate the need to first write your program down on paper.  Let's take the TurtleTalk instructions that you wrote which draw a house and turn them into a bunch of procedures.

To make this process easier, I'm going to use the editor that's built into the TG applet/application.  To open the editor in the applet, click the right mouse button anywhere in the applet and choose the Window->Add Editor menu option.  In the application, choose the Add Editor option of the Windows menubar item (at the top).  Hold the left mouse button down with the mouse located on either the CommandCenter or Editor name stripes to grow/shrink the window sizes.

All right, so we want to write a procedure which draws a house.  Click the left mouse button in the editor window and type:

  to drawHouse
followed by [Enter].  The editor will respond by opening a blank line and adding an end line following it.  The cursor will be indented for you, ready for instructions which are to be part of your drawHouse procedure.

So what now?  Where do we go from here?  How can we break down drawing the house into multiple, simpler tasks?  What are the objects that make up our house?  That's it!  Let's break the procedure of drawing the house into subprocedures, one for each object.   Our drawHouse procedure will invoke four other new procedures:

  1. drawFront - a procedure that draws the front of the house
  2. drawRoof - a procedure that draws the roof on top of its front
  3. drawDoor - a procedure that draws the front door, and
  4. drawWindow - a procedure that draws the front window.

Add invocations to these procedures to your drawHouse procedure in the editor.  Make it look like this:

  to drawHouse
    drawFront
    drawRoof
    drawDoor
    drawWindow
    end
This is a great first step.  What we just did was to think about what we needed, planned how we would break our problem down into a set of simpler problems, and then wrote TurtleTalk source code that should work.

But, this is only legal TurtleTalk source code IF we followup and define all of the drawXxxx procedures we've invoked.  In fact, the moment you move the cursor out of the text that makes up the drawHouse procedure or take focus out of the editor (by clicking the mouse outside editor) error messages will pop up.  Checkout Figure 3.1.  Any time you write or modify a procedure, the editor makes sure the procedure is interpreted as soon as it thinks you are done with it.

Figure 3.1

You could just ignore the messages - click on their close boxes - but it is best not to do this.  Instead, what you should do is to turn the lines of source code that are not yet ready into comments.  When the interpreter sees a semicolon (";") it simply collects it and all the remaining characters on the line.  This text is assumed to be a note for the programmer and anyone else reading the source code.

So, change your procedure to:

  to drawHouse
    ;drawFront
    ;drawRoof
    ;drawDoor
    ;drawWindow
    end
And now it's time to write each of the needed procedures.  Position the cursor on the "to drawHouse" line, hold down the [Ctrl] key and press the "o" key.  This opens an empty line.  You are now ready to add drawFront.  As you did for drawHouse, type in:
  to drawFront
followed by [Enter].  The editor will respond by opening a blank line, followed by an end line, and positioned the cursor, ready for you to type in the body.  Add TurtleTalk commands which get the turtle to draw the front of your house.  Once you've done this, you can go back to your drawHouse procedure and remove the semicolon on the drawFront invocation.

Repeat this process with the remaining procedures.  When you're done, you should be able to click in the CommandCenter, invoke your drawHouse procedure, and... get a house.

Did you get a house?  If not check your code and fix the mistakes.  If you did get a house, instruct the turtle to pick up the pen, move to another spot, put the pen down, and try invoking your DrawHouse procedure again.  Did you get a second house that looks like the first?  If not, why?


The Procedure: main

There is one more procedure that you should write.  Its name is main.  Why?  What's it do? 

What your main procedure should do is to initialize TurtleSpace so that it is in a known, consistent state.  When you first start interacting with the TG applet/application, is in a state where

Working in TG is highly interactive.  As you write procedures and try them out, you modify state.  You move the turtle around; you change its heading; you change the color of its pen; etc...  Testing the parts of your program is great; this helps you write a correct program fast.  But, a well written program has a known starting point and state and this is main.  It should contain all of the commands needed to intialize TG's state properly. 

Here's an example main procedure for use with drawHouse.

  to main
    home clean setheading 0
    pendown setpencolor 0 setpensize 2
    drawHouse
    end
Finally, what's with the name: main?  I've chosen this name because it is also the required starting procedure for programs written in the programming languages: C, C++, and Java.


Summary

You learned how to use comments in your TurtleTalk programs as placeholders for functionality that has yet to be programmed.

One BIG thing we learned in this lesson was how to write a program in phases:

    1. Understanding the Problem
    2. Devising a Plan
    3. Carrying out the Plan
  
These are the first three of George Polya's four steps to solving mathematical problems.  Dr. Polya wrote a very good book called How to Solve It which explains his methodology. 

I've saved the fourth step for this summary, it's:

    4. Looking Back
  
How appropriate.  Think about how you've broken large programming problems into steps of manageable size.  You've learned how to package them into procedures that have names which describe what the procedure does.  This is called procedural abstraction.

This has been your first exposure to the use of abstraction - the most powerful concept you will use as a programmer.

A Piece of History: In the mid seventies, I stopped in to see a new friend in his office.  He had stepped out for a bit, so I decided to wait.  I checked out his bookshelf and grabbed a small, plain-black book that had the title "Structured Programming" written by O.J. Dahl, E.W. Dijkstra, and C.A.R. Hoare.  A quick glance at its Table of Contents and the title of one chapter written by E.W. Dijkstra caught my eye - "On Our Inability To Do Much."  I scanned the chapter and knew this book was monumental; I had to buy a copy and read it.  This book is still in print, more than thirty years after it was published.  What this lesson has attempted to introduce to you was at the heart of the matter in Dijkstra's contributions to this wonderful book.


Back to Table of Contents
Back to previous Lesson ( TurtleTalk Commands )
On to next Lesson ( TurtleTalk Iteration )