|
BFOIT
Introduction to Programming Defining Your Own Commands |
|
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.
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.
You need to get the turtle to:
- OR -
- OR -
This is hard to describe; so, I'm choosing not to go any further with it. But, it is a way of looking at the problem.
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.
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 invisiblePseudo-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.
| 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.
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?
| TurtleGraphics Applet |
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:
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.
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:
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 45a few times... What does this do? cool, huh?
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.
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 drawHousefollowed 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:
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 drawFrontfollowed 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:
I've saved the fourth step for this summary, it's:
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.
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.