Structured Programming Style

21.1 Principles

Top-down design: break the problem into steps, each step into SUBs/FUNCTIONs, until each piece is simple.

Single entry, single exit blocks: use IF, SELECT CASE, FOR, DO, and procedures instead of GOTO.

One job per procedure: LoadLevel, DrawBoard, CheckCollision — if you need "and" to describe it, split it.

Local by default: pass parameters and return values; keep DIM SHARED for true program-wide state.

Named constants instead of magic numbers.

Declare everything with OPTION _EXPLICIT.

21.2 Naming and layout conventions

MAX_ENEMIES, SCREEN_W playerX, lives SUBs / FUNCTIONs PascalCase verbs / nouns DrawPlayer, Distance# Enemy, Vec2 isAlive, hasKey 4 spaces per block level

21.3 Refactoring spaghetti code

10 INPUT "N"; N
20 IF N < 0 THEN 10
30 S = 0: I = 1
40 IF I > N THEN 80
50 IF I MOD 3 = 0 OR I MOD 5 = 0 THEN S = S + I
60 I = I + 1
70 GOTO 40
80 PRINT S
90 INPUT "AGAIN (Y/N)"; A$
100 IF A$ = "Y" THEN 10
OPTION _EXPLICIT
DIM n AS LONG, again AS STRING

DO
    n = ReadNonNegative&("N")
    PRINT SumOfMultiples&(n)
    INPUT "Again (Y/N)"; again
LOOP WHILE UCASE$(again) = "Y"
END

FUNCTION ReadNonNegative& (prompt AS STRING)
    DIM v AS LONG
    DO
        PRINT prompt;
        INPUT v
    LOOP WHILE v < 0
    ReadNonNegative& = v
END FUNCTION

FUNCTION SumOfMultiples& (limit AS LONG)
    DIM i AS LONG, total AS LONG
    FOR i = 1 TO limit
        IF i MOD 3 = 0 OR i MOD 5 = 0 THEN total = total + i
    NEXT
    SumOfMultiples& = total
END FUNCTION

21.4 When GOTO is acceptable

Modern BASIC rarely needs GOTO. Accepted uses: ON ERROR GOTO handlers (required), and occasionally jumping out of deeply nested loops — though a flag variable or moving the loops into a SUB with EXIT SUB is usually cleaner.

🧪 Part II Exercises

Write FUNCTIONs Celsius!(f!), IsPrime%(n&), and DigitSum%(n&), and a SUB PrintTable that uses them to print a formatted table for n = 1..30.

Demonstrate by-reference vs. by-value passing: write a SUB DoubleIt that doubles its parameter, and call it with DoubleIt x, DoubleIt (x), and CALL DoubleIt((x)).

Write recursive FUNCTIONs for power (Pow#(base#, exp&) using fast exponentiation), sum of digits, and string reversal.

Read an unknown number of integers into a dynamic array with REDIM _PRESERVE (doubling the capacity), then print the mean, median, and mode.

Create a TYPE Student with name, three marks, and average; store 5 students in an array, compute averages, and print a report sorted by average.

Implement Split%, Join$, Trim$, and PadLeft$ string utilities and test them on edge cases (empty strings, delimiters at both ends).

Write a quiz program that loads questions, choices, and answers from DATA statements and reports the score.

Add error handling to a file viewer: handle "File not found", "Path not found", and "Permission denied" with friendly messages.

Build a simple address book that saves contacts to a CSV file with WRITE # and reloads them with INPUT #.

Build a product inventory on a RANDOM-access file: add, view by record number, update stock, and list all records.