home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C!T ROM 2
/
ctrom_ii_b.zip
/
ctrom_ii_b
/
PROGRAM
/
BASIC
/
QBS_0103
/
SQBC010.DOC
< prev
Wrap
Text File
|
1993-04-30
|
8KB
|
217 lines
┌───── Structured QuickBASIC Programming ─────┐
│ ╒═════════════════════════════════════════╕ │▓
│ │Single Entry and Exit in QuickBASIC Code │ │▓
│ ╞═════════════════════════════════════════╡ │▓
│ │ an article written by │ │▓
│ │ Quinn Tyler Jackson │ │▓
│ │ of │ │▓
│ ├─────────────────────────────────────────┤ │▓
│ │ JackMack Consulting & Development │ │▓
│ │ #302-9085 Gildwood Drive │ │▓
│ │ Burnaby, British Columbia │ │▓
│ │ V3N 4L9 CANADA │ │▓
│ └─────────────────────────────────────────┘ │▓
└─────────────────────────────────────────────┘▓
▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
WORD COUNT: 1,150
Flesch-Kincaid: 9th grade
A feature of maintainable code in any language is modular
single entry and exit. By definition, single entry and
exit involves a simple principle: passing control to a
module in only one manner and returning from the module in
a similarly static fashion. This keeps code flow clear
and understandable for future revision and review, since
whoever inspects the code begins the project with the
assumption that any given module is accessible in one way,
and will relinquish control in just as set a manner. This
presumption frees the inspector to examine the program
flow, without cluttering his mind with random hops and
jumps triggered by numerous factors in the system.
First to consider is single entry. Structured philosophy
dictates that a module should gain control in one way
only. For example, if a module gains control with the
press of a key, it should not gain control through any
other means. A programmer reading the code will know that
the only means of calling the module is by pressing a key,
and he will not have to worry about any other event
getting in the way of this. Imagine the difficulty added
to program debugging if the same module were accessible by
a timer tick, or a byte arriving in a modem buffer. How
would the programmer know if keyboard, modem, or timer
code caused a bug?
The importance of single entry becomes even more apparent
when modules begin to interact. Miscellaneous accesses
juggle about control between modules, and these in turn
randomly access other modules and become part of an ever
more complex process. Each module's having only one entry
point greatly simplifies tracking down a bug or series of
bugs in such a complex system. The fewer stitches used to
hold the whole system together, the better off the whole
system is for it.
As a pseudocode example of a module that has multiple
entry points:
IF KeyPressed = TRUE THEN React
IF ModemBuffer = FULL THEN React
IF TimerTicks = 5 THEN React
MODULE React
BEEP
END MODULE
Although simple, this bit of code shows the problem. Each
of the events KeyPressed, ModemBuffer, and TimerTicks can
give control to the same module called React. In short,
React has three entry points, which complicates debugging
and maintenance accordingly. But, how to work around this
problem? What if you want all three situations to pass
control to a procedure that beeps? Are you supposed to
write this, instead?
IF KeyPressed = TRUE THEN BEEP
IF ModemBuffer = FULL THEN BEEP
IF TimerTicks = 5 THEN BEEP
This would accomplish the same task, but suppose the
module React were two hundred lines long, instead of just
a simple BEEP? Would those two hundred lines have to be
repeated three times, once for each triggering event? No.
A simple method to avoid repetition in single entry code
involves a type of indirection. At first, it looks a bit
strange and seems impractical, but further investigation
shows that it simplifies code:
IF KeyPressed =TRUE THEN KeyReact
IF ModemBuffer = FULL THEN ModemReact
IF TimerTicks = 5 THEN TimerReact
MODULE KeyReact
React
END MODULE
MODULE ModemReact
React
END MODULE
MODULE TimerReact
React
END MODULE
MODULE React
BEEP
END MODULE
In simple, one-page programs, this seems ridiculous. In
theory, however, this indirection forces the modules of
the system into the single entry model. ModemReact
responds to modem events, TimerReact to timer events, and
so on. Now, instead of having three entry points, React
responds to one event: being called as a standard module.
React, having been buffered by indirection, now serves
only one purpose, not three. Moreover, should it happen
that the code is to be modified, the programmer, having
isolated the three triggering events, can modify the
keyboard, modem, or timer code as separate units, and does
not have to consider anything other than the events he
wishes to alter. The concept of a single purpose per
module is tied closely to the single entry and exit
principle. Indirection isolates the module from the three
separate events to the extent that a programmer asked to
debug the code can uncover problems arising in the
keyboard, modem, or timer code without having to
simultaneously juggle the three about in his head.
Program flow becomes comprehensible.
Single exit, the first cousin of single entry, dictates
that there should only be one way to pass control from a
module. QuickBASIC, with its EXIT SUB and EXIT FUNCTION
commands, could conceivably compile this code:
SUB Foo (variable AS INTEGER)
IF variable = 1110 THEN
SomeGlobalVariable = 3
EXIT SUB
' The above line passes control from this module.
END IF
FOR a = 1 TO 10
IF variable = INT(RND * 100) THEN
SomeGloabalVariable = 8
EXIT SUB
' So does the above line, but for different reasons.
END IF
NEXT a
DO
KeyPressed$=UPCASE$(INKEY$)
LOOP UNTIL KeyPressed$ <> ""
IF KeyPressed$ = "Y" THEN
SomeGlobalVariable = 9
EXIT SUB
' And so does the above, for yet another reason!
END IF
' As will the following code, for another!
SomeGlobalVariable = 5
END SUB
An examination shows that control is passed from Foo if
one of three conditions are met: first, if variable is
equal to 1110; then, if variable is equal to one of ten
random numbers between 1 and 100, and finally, the module
passes on control if the user presses a 'Y' on the
keyboard. If none of these conditions are met,
SomeGlobalVariable is set to 5 and control passes on when
program flow reaches the logical end of the module. (One
could argue that, for simplicity's sake, the best place
for control to be passed on is at the end of a SUB or
FUNCTION, since that is the default behavior of most
languages.) Four different ways to exit one module.
This is unacceptable behavior in the single exit model,
which demands that a module exit under only one condition,
so that the programmer examining the code can state: "I
can be sure why Foo gave up control." In unison with
single entry, this makes debugging a pleasure! On the
other hand, multiple entry coupled with multiple exit can
be a nightmare. . . .
A possible reworking of the above messy code might be:
SUB Foo (variable AS INTEGER)
SomeGlobalVariable = 5
IF variable = 1110 THEN
SomeGlobalVariable = 3
ELSE
FOR a = 1 TO 10
IF variable = INT(RND * 100) THEN
SomeGloabalVariable = 8
END IF
NEXT a
END IF
IF SomeGlobalVariable = 5 THEN
DO
KeyPressed$=UPCASE$(INKEY$)
LOOP UNTIL KeyPressed$ <> ""
IF KeyPressed$ = "Y" THEN
SomeGlobalVariable = 9
END IF
END SUB
As modified, Foo only exits under one circumstance: when
the program flow reaches the logical end of the module.
This simplifies things considerably and consequently makes
debugging and maintenance more manageable. And of course,
manageable code is the objective of any structured
approach to programming, whether it be in QuickBASIC or
C++.