Learning a programming language is similar to learning a
natural
language such as English. Although the "vocabulary" of a programming
language is usually less than 100 words, there are many rules that
govern the correct formation of sentences or "statements" in the
language. This "grammar" of a programming language is quite complex,
and the grammatical rules are very detailed and precise. During natural
language conversation you can get away with considerable ambiguity or
grammatical inaccuracies and still be understood. Not so with
programming languages. The myriad rules which dictate what constitutes
a correct program statement must be followed with unerring accuracy.
Anyone who has learned to speak a second language will agree
that
the best way to gain fluency is to visit a country where that language
is spoken. By surrounding yourself with others who are speaking and
listening in that language you are creating a situation that offers
abundant feedback for learning. By conversing in a new language on a
daily basis you get lots of practice and receive lots of feedback about
your attempts.
In the same way, you can best learn a programming language by
creating a situation that offers lots of feedback. Fortunately, the
computer itself offers such a situation, since its interactive nature
provides lots of feedback about our attempts to "speak" this new
language. You could try to learn all the rules for formulating correct
program statements solely from the book, but that would be like trying
to learn correct English grammar from a book without ever speaking or
listening to the language.
The Empirical Method
As you take advantage of the computer's interactive nature you
are
engaging in the same empirical methods that are relied on by all
sciences. The way you learn a programming language is analogous to a
scientist studying the natural world. A physicist, for example,
performs "experiments" by dropping balls in an attempt to understand
how gravity works. The physicist is gathering evidence about some
physical phenomenon in order to gain insight into the underlying
physical principles which govern the behavior being observed.
In the case of studying a programming language, the phenomenon
being
observed is a computer program. When executed on the computer this
program has certain externally observable behaviors. By systematically
experimenting with the program, gathering evidence about its behavior,
you can construct inferences about the principles or rules which
dictate how it operates.
Eventually the scientist will conceptualize his or her
observations
into a theory from which one can make predictions about the behavior of
the phenomenon in different situations. Similarly, as you are
"discovering" how the programming language behaves, your understanding
of the language can be measured by the degree to which you can make
accurate predictions about the way the language features operate in
different circumstances. Eventually this will enable you to construct
programs of your own design.
Lab Notebook
A scientist working in a lab proceeds in an organized,
systematic
fashion, making exhaustive notes of his or her procedures and
observations. The reasons for this are twofold. First, when exploring
an unknown area, one never knows which details may be significant, so
it's important to record everything. Secondly, detailed documentation
of the procedures followed and results obtained is necessary to enable
others to replicate the scientist's findings.
Similarly for your explorations, proceeding in a careful,
organized
manner is the key to being effective. If your work habits are sloppy,
unorganized, or haphazard, your work won't make any sense and trying to
arrive at any meaningful understanding will be difficult. The
unrelenting precision and accuracy required by the computer demands
from us an uncommon degree of care and attention to detail. Without a
systematic approach, tiny but significant details of the programming
language may elude you and lead to misunderstanding and confusion.
Although you may not have to share your findings with other
researchers, good lab notes become a valuable reference to which you
can return when you encounter similar situations in the future. All too
often you will find yourself staring at an obscure error message from
the computer that seems familiar, but you can't recall what it means.
If you have kept good lab notes, then it's a simple matter to look up
how you dealt with that problem at an earlier time. If you end up
seeking outside assistance with computer problems, having a detailed
record of your difficulties will make it much easier for an expert to
diagnose your problems.
It is strongly recommended that you use a notebook to record
your
explorations. Use a cloth bound or spiral bound notebook to record
everything you do at the computer. Write legibly and include enough
detail that another student reading your notes could replicate your
experiment. For each experiment you undertake, document the purpose of
the experiment, the expected results, the step by step procedures that
were followed, the actual results you observed, and the conclusions --
what you learned. (You might also keep track of dates and time spent as
an aid in time management). Several lab notebook examples are included
at the end of this chapter.
At first you may feel reluctant to keep a lab notebooks, as it
seems
like tedious busywork. However, as you learn how "picky" and demanding
the computer is, if you make the effort to keep a good notebook you
will find it enormously helpful.
In the laboratory, it is said "there are no mistakes, only
surprises." Every thing you do on the computer is a chance to learn
something, regardless of whether or not it turns out as you expected.
So don't try to make your lab notes look like everything worked
perfectly. Lab notes are not intended for publication, they are the
place where you document your learnings. It's important that you
clearly explain every "surprise" you encounter and what you learned
from it. Eventually all these little insights will start to accumulate
into a coherent understanding of the computer and the software
controlling it.
Constructing Experiments
The most effective way to learn programming is to get your
hands on
the computer, practice "speaking" this new language, and observe the
feedback you get. If you are taking a formal course in programming, the
instructor will no doubt provide you with exercises and activities to
perform on the computer as a way of giving you hands-on practice. Some
textbooks are published with an accompanying laboratory "workbook." If
such a workbook is available to you, undertaking the suggested
activities would be a good place to begin your lab explorations. The
workbook activities are usually very well structured and you simply
work through them in a cookbook fashion.
But if you are an independent learner, you may not have the
luxury
(or burden, depending on your viewpoint) of instructor assigned
activities. You may not have a workbook with already prepared
activities for you to perform. Without these externally prescribed
guidelines for proceeding, where do you begin?
Perhaps the best approach to exploring a programming language
is to
take advantage of sample programs provided in a textbook. Most
textbooks, tutorials, and other programming handbooks present numerous
example programs to illustrate the major language features. These
examples alone, even without the accompanying explanations, are a
valuable resource for learning.
Unfortunately, the textbook doesn't explain how to take
advantage of
these sample programs. The examples are presented as though just by
reading them you will gain the necessary understanding. What the
textbook doesn't say is that you should interact with these
examples. Reading them isn't enough. In order to truly understand these
examples, you need to enter them in to the computer and explore them.
What is being suggested is an open ended kind of inquiry, not
a
rigid method or procedure. There is no right or wrong way to proceed.
Just as many a curious child has pulled the back off a new toy to try
to see how it works, the textbook examples should be seen not as
"tablets of wisdom," but as toys begging to be taken apart and
experimented with.
Unfortunately, this kind of playful exploration requires an
inquisitive frame of mind that most school experiences do not
encourage. After a dozen years of public school your curiosity may have
retreated into a back closet in your mind. So the challenge of
proceeding independently to explore the computer may ask you to dredge
up old strategies you have not used in a long time.
Another mind-numbing characteristic of formal schooling is the
reduction of complex ideas into simple multiple choice and
fill-in-the-blank questions. You may have become adept at figuring out
how to succeed on tests, yet still often feel unsure that you grasped
the entire picture. Writing a computer program, on the other hand, is a
very holistic, creative endeavor, and the fragmented approach to
understanding doesn't work very well. You may have to abandon your
habitual "plug and chug" approach to problem solving.
The next section will present some specific exploration
strategies
to help you get in the frame of mind for interacting with the textbook
examples. You can use these strategies as you construct your own
experiments. These guidelines will not tell you exactly what to do,
instead they describe strategies and tactics. It's up to you to create
the actual experiments that you carry out for each new topic you
investigate. For each program that you explore, you will need to
consider what important new language features or techniques are being
illustrated and build an experiment which will focus on the behavior of
particular interest.
This may be a new challenge for you since most teachers don't
require students to invent their own assignments. But with programming
languages, an essential learning skill is to be able to design your own
experiments to learn about the rules of the language that you don't
understand. The guidelines below provide some strategies that you can
use, but applying these strategies will require some creativity and
imagination on your part, as each program you encounter will be
different. Your own natural curiosity and inquisitiveness will usually
be all the spark you need to get your creative juices flowing.
LABORATORY EXPLORATION STRATEGIES
Typing example programs.
The first very simple, yet surprisingly helpful activity, is
to
enter a program into the computer by typing from a source listing in
the textbook. Especially when you are just beginning, you will discover
that there are very precise punctuation rules for the language you are
studying. Every symbol must appear in exactly the correct relationship
to other symbols. There is no better way to familiarize yourself with
the tiny details of programming syntax than by sitting at the keyboard
and reproducing a program exactly as it is shown in a textbook example.
Select any of the early examples from the textbook, enter it
into
the computer with a text editor, then compile it. (Refer to section
X.X). If you have made no mistakes, the program should compile without
errors. If you made a typing mistake, or didn't accurately copy the
code from the textbook, then compile errors may result. You should be
able to resolve these errors easily enough by double-checking your
work, comparing what you typed against the textbook.
After you have typed your first few programs, you will start
to
feel comfortable with the punctuation rules for the language, and
typing programs by hand will become less worthwhile. Most textbooks
provide a diskette which contains the source code to the example
programs. If such a diskette is available to you, it will save you from
manually typing in all the examples. If you don't have a source
diskette, you might contact the instructor to find out if one is
available. Recently some textbook authors have also begun to make the
textbook examples available over the Internet.
Running example programs.
Select a program that is an interesting example of the topic
you
are studying. If your text includes "case studies" these often make
excellent examples. The case study usually contains a partial or
complete sample execution of the program. Read the case study to
determine what the program is supposed to accomplish. Try to locate a
sample execution that shows what input data is provided to the program,
and what the output should look like.
Then compile the actual source code and run it. Enter the
same
input data as given in the sample run in the textbook. Obviously, the
expectation is that your execution should yield the same results.
If the program doesn't compile then perhaps you have not
followed
the proper procedure. Double check that you are using the proper
commands. (Refer to section X.X) It's also possible that the source
code from the diskette differs in some small way from what is printed
in the text. Scrutinize the code and compare it to the text. Often you
can discover the discrepancy yourself.
If the execution doesn't yield the same results as the book,
perhaps you entered different input data. Again, it's possible that the
textbook could have a typographical error, or that the source code
distributed for the example programs is not exactly the same as what is
printed in the textbook. If you can't isolate the discrepancy easily,
you might just skip it and try a different example.
If you are still unsuccessful after carefully reviewing your
resources, you may need to enlist outside assistance from some
knowledgeable person.
Testing example programs.
The next step in learning about an example program is to
study how
it behaves under different circumstances. By observing how it responds
to various input conditions, you can gain a better understanding of
what the program can accomplish as well as its limitations.
In the previous exploration, you succeeded in running the
program
using input data provided in the textbook. Now you are going to carry
out your own testing on the program. First you must have a clear
understanding of what the program is INTENDED to accomplish. Read the
textbook explanation again and be sure to have a clear picture in your
mind of the program's purpose. Next, determine what kind of input data
is required and what outputs will be produced. Write a "test plan" in
your lab notebook, by inventing appropriate input data items, and
manually calculating the expected results. Construct as many test cases
as you can think of to create a wide variety of input conditions. You
may want to use a table format as in the attached examples, to record
the purpose of each test case, the input data and the expected output.
Then compile and execute the program code. Carry out your
test plan
by entering the input data and recording the actual results provided by
the computer. If the actual output is different than what you
predicted, note this as a "discrepancy", (perhaps marking it with a
question mark).
When you have carried out all your test cases, review the
results
to assess if the program is working properly. Write a "testing summary"
in which you comment on which tests succeeded and which failed. Attempt
to explain the nature or cause of each "discrepancy" as best you can.
Summarize what you learned about the program's capabilities and
limitations.
If there are aspects of the program you feel need repair or
improvement, you might note these as potential enhancements for future
explorations.
Examining source code.
Now that you are thoroughly acquainted with the externally
observable behavior of the program, you should study the source code
that is responsible for producing this behavior. At first glance much
of it may appear mysterious, but in fact each facet of the source code
somehow contributes to the program's overall operation. Ultimately, if
you have a complete understanding of the program, you should be able to
explain the role each statement plays in achieving the program's
outcomes.
Begin by reading the source code and see how much of it makes
sense
to you. You might try to write a remark in English in which you explain
each statement in the code. Write a short summary of what you are able
to comprehend. Don't worry if it makes little sense to you at the
moment. The explorations that follow will help you sort out the pieces
of the puzzle.
You might try to identify which parts of the program
correspond to
its observable behavior. Can you determine where the inputs are
obtained and the outputs displayed? Which parts are responsible for the
major calculations? Where are the control or logic structures? For now,
make a list of questions about everything that is unclear or puzzling,
or about which you are simply curious.
Bebugging.
"Bebugging" means intentionally trying to introduce errors
into an
example program from the book. Use a text editor to make some small
superficial alteration of the syntax of the language statements, such
as omitting a parenthesis, changing a comma into a semicolon,
misspelling a keyword, or changing the order of elements in the
program. The questions you generated in the previous step may give you
ideas for things to try. Compile the program and observe if an error
message is generated by the compiler. Carefully record each step in
your notebook, particularly the verbatim error message. Undoubtedly you
will encounter these same messages in the future, and if you have them
written in your lab notebook it will be much easier for you to diagnose
the problem.
If no errors result, run the program and observe any change
in
behavior. Describe the effects in your notebook. In this activity and
the ones which follow, you are attempting to make systematic changes to
the code and carefully note the results. You might think of it as a
kind of detective work where you are gathering clues from which you can
begin to make inferences about the underlying mechanisms in the
program.
Syntax changes.
"Syntax" means the way the symbols are put together and
relate to
each other in a statement. It refers to spelling, punctuation, and
other aspects of the form of the statements, not their
underlying meaning. As you begin to grapple with understanding the
workings of the program, the most obvious issues to explore are the
syntactic aspects of the language feature you are studying. Usually
programming languages don't allow much deviation from the rules for
correct statements. Almost any variation from the precise rules will
cause an error, as you discovered during "bebugging" experiments.
However, it is sometimes possible to alter the syntax so that you DON'T
cause an error. An important first step then is to determine which kind
of syntax changes are legal and which are not.
Think of a way to experiment with the statement syntax,
changing it
in some way, yet still producing the same result. The intent is to find
some different yet still correct way to produce the desired result. For
example,
Alternate solutions.
"There's more than one way to skin a cat." As the old maxim
implies, there are usually multiple solutions to any problem. Once you
start to learn about different language features, see if you can invent
a different approach which accomplishes the same result. (Again, the
difference between "code synonyms" and "alternate solutions" is not
important. The intent here is to attempt more ambitious changes to
involve different language features.) For example, use a WHILE loop
instead of a FOR loop to control the number of repetitions.
Code improvements.
Invent some small improvement to the program that involves
adding
new statements, but doesn't affect the overall structure of the
program. For now, avoid changes that would alter the underlying logic
of the solution. Of course there are many possible improvements, so you
should focus on experiments which help you understand the language
feature being demonstrated by the example program.
Approach this task in a systematic fashion, recording in your
lab
notebook what you intend to accomplish, how you go about it, what
problems you encountered, and what results your observed. Be sure to
have a test plan, so that you will know if your solution produces the
correct results.
Examples:
Improve a program that asks for a person's height, to have it
obtain the person's weight as well.
Improve a program that computes the area of a circle, to have
it
compute the volume of a sphere with the same radius.
Improve a program that determines the hottest day of the year
from
a list of temperatures, to also have it compute the coldest day.
Improve a program that computes a total of some values to
have it
also compute the average.
Improve a program to be more flexible so that values
previously
coded as constants can be entered by the user.
Improve a program that relies on input being lower case so
that it
is case insensitive.
ADVANCED EXPLORATIONS
As you start to gain confidence in your programming skills,
you
might undertake more sophisticated explorations.
Program enhancements.
Enhance the program so that some new functionality is added.
This
usually requires reworking of the logic of the solution, changing or
enhancing the underlying algorithm. Be sure to plan these changes on
paper first, and check your logic carefully. Next translate algorithms
into program code. Create a test plan to verify that your changes are
correct.
Examples:
Change a program that accepts a fixed number of input data
items so
that the user may specify how many data items are to be entered.
Perform validity checking on input data to make sure it is
the
proper range.
Change a program that receives all inputs from a data file to
one
which interacts with the user to obtain input.
Change a program that relies on "coded" inputs (such as MTWRF
for
days of the week) to be able to accept the actual name, e.g. "Monday."
Enhance a program so that when the computations are
completed, it
asks the user if they would like to perform another run before quitting.
Enhance a program so that the user has the option of saving
the
results to a data file.
Convert a program which displays vertical bar charts to
display
them horizontally.
Add an interactive "menu" to a program so that instead of
carrying
out its functions in a sequential manner, the user is allowed to select
which operations to perform.
Program reformulation.
To "reformulate" a program is transform it in such a way that
it
performs a different task. This implies a major revision. Quite likely
the overall structure and logic of the program will be altered.
Examples:
Reformulate a program which calculates a water utility bill
so that
is calculates the electric bill.
Reformulate a program that pays salesman on an hourly wage to
one
where pay is based on commission.
Reformulate a program which determines student grades based
on a
curve to one where grade is based on a straight percentage.
Reformulates a program which assists in preparing the user's
federal tax forms so that is prepares the state tax forms.
Reformulate a program that looks up items in an inventory
file so
that it can update items in the file.
Program assembly.
When building larger programs, it is desirable to not
"reinvent the
wheel." When possible, it is good to take advantage of already written
code. Software "reuse" is a strategy for assembling parts of different
programs together to create a new program. Prewritten software
components often exist in libraries for common tasks such as math
functions, text manipulation, graphics, and so on.
For these explorations you might experiment with
incorporating
prewritten routines into your own programs. You might simply invoke
functions from a library, or you might "cut and paste" code from
example programs in the textbook.
<>
CONCLUSIONS
When you have finished your explorations, it's important to
take
time to reflect on what you learned. It's helpful to write a concluding
paragraph that summarizes the main points you investigated and what you
learned from your explorations.
The purpose of these lab explorations is to help you master
the
syntax and semantic rules for correctly written programs. There isn't a
required number of exercises to work, or a specific set of assigned
problems to complete. Instead, these guidelines are open ended to allow
you to explore whichever topics are most interesting, or to investigate
ideas that you find difficult. Each example program you investigate is
designed to illustrate certain language features. Your explorations
should focus on the key features of the example, and you should
continue experimenting until you understand the proper usage of the
language feature being illustrated