Introduction to Programming
Defining Your Own Operators
and Hierarchy
In this lesson, you will learn
The programs you are now writing are starting to get big and they are taking hours to write. In a few lessons, you will be writing programs that take many hours to complete. This means that the programming will be spread over days. Each time you return to continue programming, you need to pick back up where you left off. My point is that your programs need to be easy for you to read so that you can refresh your mind on what's done and what's left to do. I suggest that you get into the habit of giving names to many of the numbers that are starting to become ubiquitous in your programs.
The most obvious case is the numbers for the colors that you specify to the setpencolor command? I have trouble remembering many of the color numbers. So, what I have done is to write little procedures that output numbers corresponding to the color the procedure's identifier represents.
Here are a few examples:
to blue
output 1
end
to forest
output 10
end
to salmon
output 12
end
This binding of a number to a meaningful identifier is what's
called a symbolic constant in programming terms.
Once defined, you can use these procedures as the input to setpencolor. The colors above are the colors I used in my seascape TurtleTalk program. Here is what part of my main procedure contains - the part that uses the color procedures.
to main
hideturtle
setpencolor blue
waves -240 20
waves -130 -15
setpencolor forest
fish 100 -100
fish 50 -150
...
Using the procedures blue and forest makes the program
much easier to read.
to printCircleCircum :radius
println product 2 product 3.14159 :radius
end
It would be more useful to separate the println functionality from
the computation piece. It's simple... Just replace println
with output.
to circleCircumference :radius
output product 2 product 3.14159 :radius
end
Notice that I changed the name of the procedure. You always want
the name of the procedure to reflect what it does. This is how
we achieve our abstraction.
This new procedure, now an operator, is simple to use with the println command, e.g.,
println circleCircumference 4
"25.13272" is displayed in the CommandCenter window.
Use the following TurtleTalk applet to try it out for yourself.
| TurtleGraphics Applet |
OK, now for an operator that would have been nice to have in one of the programs we wrote in the last lesson. To refresh your memory, we needed a couple of random numbers in ranges other than the standard 0...x-1 provided by a "random x" operator. We needed random numbers in the range -285...235 for the X coordinate and in the range -225...175 for the Y coordinate.
I want a new operator, let's call it randomInRange, which produces an output - a number that's in any range of numbers I provide as inputs. As an example, for the invocation "randomInRange -50 50" I want an output that is random and is greater-than or equal-to -50 AND is less-than or equal-to 50.
Here's the skeleton.
to randomInRange :min :max
; output <random number gtr-or-eql :min and less-or-eql :max>
end
At this point, don't hesitate to play around in the TurtleTalk applet to figure out what you need to do. Follow the steps we've been using to write all of our TurtleTalk programs.
1. Understanding the Problem (figure out what you know,
and what you don't know)
2. Devising a Plan (write a pseudo-code description of
what to do, draw a plumbing diagram
or diagrams to visualize what you
will do)
3. Carrying out the Plan (type in the TurtleTalk code
to do the job and test it;
does it work? if not, verify
your code matches what you
developed in step 2 and review
what you came up with in
steps 1 and 2)
To get you started... If you think about it, your output needs to be at least what is provided for :min when randomInRange is invoked. Since random returns 0 at a minimum, you are going to have to add :min to the output from random in the output produced. So, our pseudo-code now looks like:
to randomInRange :min :max
; output sum :min random <magnitude of range of numbers>
end
At this point, I suggest that you write an operator named magnitude. Here's the expanded pseudo-code:
to magnitude :min :max
; output <magnitude of range of numbers>
end
to randomInRange :min :max
output sum :min random magnitude :min :max
end
OK... finish the procedure.
Use repeat to test your code. If it doesn't work, help is on
the way - read the next section. If your code works, congratulations!
&nbpsp;Now read the next section because it's a really cool feature you
are sure to use in the future.
TRACE - A Debugging Tool
Time for you to learn about a feature in TG, tracing, that will help
you understand what's happening when you're program is being executed.
trace is a directive you enter into the CommandCenter window of
TG. trace is similar to a command, but it can't be put into the
body of a procedure. It directs TG to print out very useful stuff as
your program is interpreted.
So you have your magnitude and randomInRange procedures entered. In the TG CommandCenter window, type:
trace magnitude
print randomInRange -4 4
Since TG has been directed to trace the procedure magnitude, what you should see is:
Entering magnitude -4 4
Exiting magnitude 8
TG let you know that magnitude was invoked with the inputs: -4
and 4. It's body was executed and its output was 8.
Well, with this information, you can see that there is a problem with the code I gave you. There's a bug in it. randomInRange -4 4 will never output 4.
random 8 outputs a number in the range 0 - 7. To get an output of 4 we need to give random an input equal to the output of magnitude plus 1.
Fix the bug (if you hadn't discovered it and fixed it on your own)...
Finally, modify your program from the last lesson that draws boxes at
random locations so that it uses randomInRange.
Hierarchical Structure - Why It's Important
A hierarchy is a grouping of
things into levels. There is a "top" level and then a series of lower
levels under it. It's all about abstraction. At each
level you describe a concept with enough detail for you to have a good feel
for what lies below it.
In the previous lesson you wrote a program that drew a series of houses, each similar (they all had a roof, door, and window) but different (their heights and widths varied). The elegant solution to this problem was to write procedures that drew the pieces of the house, e.g., the door, the window, etc... Each of these procedures had inputs that were the desired location and size of the house. Each procedure adjusted itself to fit this criteria. Each of these procedures was composed of a bunch of primitives, i.e., penup, pendown, setxy, forward, quotient, etc... You had to know all of these, what they did. But, the next level up in the hierarchy - your DrawHouse procedure - there were NO primitives needed. Your DrawHouse simply combined the procedures that you had written. Here is my version:
to DrawHouse :x :y :height :width
DrawFront :x :y :height :width
DrawRoof :x :y :height :width
DrawDoor :x :y :height :width
DrawWindow :x :y :height :width
end
This shows the power of abstraction and hierarchy.
With abstraction, a programmer does not need to know how a procedure does
what it is documented to do - just that it does it. Hierarchy lets
a programmer build more and more complicated structures, one on top of
the other. Figure 7.2 show the hierarchy of the
DrawStreet program.
|
| Figure 7.2 |
At the highest level in the program's hierarchy, all it had to know about was the procedure: DrawHouse. Given it, the street was drawn as such:
to DrawStreet
DrawHouse -265 -100 100 150
DrawHouse -105 -100 120 100
DrawHouse 5 -100 200 120
DrawHouse 135 -100 70 110
end
And, the only thing that someone needs to know in order to modify this
program to draw a different set of houses is what the inputs to
DrawHouse are. There is no need to know even a single
primitive procedure! This is very powerful and is the heart of
programming.
Building things in hierarchies is very common in computer software. One example are the file systems provided by operating systems. File systems have a top-level, often referred to as the root of the file system. Under the root, there are subdirectories like "My Documents" and "Program Files" and under these are more subdirectories.
And, speaking about graphical representations of your programs, I ended the lesson with a sales-pitch to get you to write programs that have well-defined hierarchies.
| New TurtleTalk Procedures Used In This Lesson | |||
| Name | Input | Description | Example |
| OUTPUT | value | Execution of the current procedure is complete. output's input (value) is passed back to the instruction that the current procedure's invocation is part of. | OUTPUT 1 |