Modular Programming
 By David Tordrup

 

Contents:

1.0 Introduction

2.0 The basics of modular programming
2.1 Subs
2.2 Functions
2.3 Where to use SUBs and FUNCTIONs

3.0 Going into the details of subs
3.1 Getting data into modules
3.2 Global Variables
3.3 Module Interface
3.4 Commands you can't use in a sub

4.0 Going into the details of Functions
4.1 Using functions for calculations

5.0 Summary

6.0 Closing words

1.0 Introduction
When writing large programs in QBasic, it is vital for the debugging process that the flow of the program can be understood easily. If GOTO and GOSUB is used a lot, the program acquires a spaghettilike structure, making it extremely hard to track down and remove bugs in the source. This is why modular programming is such a good idea. This particular method of programming lets you divide your program into smaller tasks that can be solved individually, creating an easy-to-read source code, that also takes less time to debug.

2.0 The basics of modular programming
First of all, a module is a chunk of code within a program that performs a specific task, and typically has a name that describes that task. A module that collects input from the user should therefore be called "GetInput" or something along those lines, but all valid variablenames can be used. Giving the module a descriptive name does however make it easier for yourself and other people to understand the source. There are two types of modules: SUBs and FUNCTIONs. These two terms will be used throughout the tutorial, so here's a brief description of them:

2.1 Subs
SUB is short for 'Subroutine'. A SUB may contain most QBasic statements, although some statements may be used only in the main code. SUBs are useful when you need several lines of code to complete a single task, for example when printing help-screens for the user, or creating windows. All variables used in a SUB are local, which means they start at 0 or null every time the SUB is called, unless they are dimensioned as global variables in the main code (more on this later). You can also pass variables from the main code to the SUB, or define the SUB as STATIC, which means the variables are not reset when control is passed back to the main code. Don't worry if you don't understand the above at this point, everything will be explained in detail later.

2.2 Functions
Functions are just that. They are used in the same manner as 'built-in' QBasic functions such as RND (random number), SQR (square root) or LEN (length of a string). In general, if you can type Variable = FunctionName(arguments) and get away with it, it's a function. This is where FUNCTIONs are different from SUBs, a sub is called like a normal QBasic statement, and functions are either assigned a variable (a% = FunctionName) or used to determine the outcome of a true/false expression (IF YesNo$ = "N" THEN...)
 

2.3 Where to use SUBs and FUNCTIONs
Subs and functions may appear alike, but their uses are completely different. The following paragraph should give you some idea of when to use subs and when to use functions. A sub is best suited for a routine that requires little interaction with the main code, meaning that the outcome of any calculation in the sub shouldn't bear any significance to the main module. Functions on the other hand often provide a new value to a variable in the main code, and are therefore best suited for long or complicated calculations. In short, use subs for long routines and functions for long calculations.

3.0 Going into the details of SUBs
A new sub is created by typing 'SUB SubName' whereafter you get a blank screen with the words 'SUB SubName' and 'END SUB'. The statements in your module go between these two lines of code. It is considered good programming practice to add a few comment lines to the top of the sub describing what it does and what variables from the main code are used and/or changed.

3.1 Getting data into modules
As mentioned before, all variables used in subs and functions are local to the module, which means they are reset when command is passed back to the main code, unless the sub is defined as STATIC. If you want to use variables/strings from your main code in the module, you have two options: Global variables or the module interface.

3.2 Global Variables
If a variable or string is defined as global, it can be used and changed in all levels of the program (in all modules). This kind of variable is essential for large programs that use many variables for controlling the programflow. A global variable is defined in the main code with the following statement:

DIM SHARED Varible, Variable1..... AS TypeA, Variable2 AS TypeB

Where Type is the type of variable you are currently defining, e.g. Integer, String, Single-precision etc. (See the QBasic help for more info on variable types). When using global variables you are also forced to plan your program ahead before typing the actual code. This often makes the result of your efforts much better, as your code will be efficient and easily readable if you have planned it properly. Constants defined with the CONST ConstName = Value% statement are also global and may be used in all subs and functions without any bother.

3.3 Module Interface
An alternative to global variables is using the module interface. This has advantages over global variables in some cases, but naturally it is also inferior on some points. If you are writing a sub that performs a task based on the data passed to it from the main code, a box drawing routine for example, you would use the module interface for data-interchange. This way you could get away with typing something like 'DrawBox (1, 1, 20, 20)' instead of having to give four global variables a new value and then calling the sub. The module interface is created by adding a set of paranthesis () to the 'SUB SubName' statement:

SUB SubName (Variable%, String$)

It is now possible to pass two variables to the module (an integer and a string), by typing

SubName a%, s$

In the sub, the variables a% and s$ will be known as Variable% and String$ as stated in the SUB SubName statement. You can have any amount of variables of any kind passed to a module. This does mean however, that every time the module is called, the correct number of arguments must be passed to it. This is partly where this method is inferior to global variables. When calling a sub with arguments, you must make sure that you type the arguments in the correct order, according to the declaration of the sub, and that the arguments passed are of the right datatype (integer, string etc).

3.4 Commands you can't use in a sub
There are certain commands and statements that won't work within a module. This doesn't mean that there are some tasks that can't be solved with modules, just that you need to add a little extra code to your main program. The most commonly used statements that aren't allowed in modules are as follows:

CONST                   -  For defining global constants
DIM SHARED              -  For defining global variables
DECLARE SUB / FUNCTION  -  For initiating a module in a program
DATA                    -  Data statements can only be put in the main code

You might very well encounter other statements and commands that are illegal in modules, just try moving them into the main code.

4.0 Going into the details of Functions
A function is created in the same manner as a sub, by typing the following statement: FUNCTION FunctionName (ArgumentList%) Same as before, you now have a blank screen with the name of the function and the END FUNCTION statement. There are two main uses for functions. The first is calculating a new value based on the arguments passed to the function in the arguments list, the second is reading or calculating a new value based on input from the user or gathered from an input device.

4.1 Using functions for calculations
This is really practical if you need a fixed number of operations done on a variable from the main code. You could have a function that converted a string input from the user to all uppercase, no commas and no left/right spaces. This could be useful in a text-adventure for example. You would do this by typing the formatting code into your function module, using the name of the module as your stringname:

FUNCTION ConvString$(Text$)
ConvString$ = UCASE$(ConvString$)               ' Convert to uppercase
ConvString$ = LTRIM$(RTRIM$(ConvString$))       ' Remove left/right spaces
.....
END FUNCTION

In the main code you would put something like

INPUT Text$
Text$ = ConvString$(Text$)

Whereafter your string Text$ will be changed to whatever your sub does to it. It saves a lot of space in the main module, and makes it easier to read.

4.2 Using functions for getting new values
A function may also be used to create a new variable. This means that the function collects input from the keyboard or another input device, and gives it to the variable in question. For example, if we wanted to create a function that waited for a single keypress from the user, printed it on the screen, and passed control back to the main program, we would have something like this:

FUNCTION GetChar$
DO                              ' Start reading-loop
  Temp$ = INKEY$                ' Read the keyboard
LOOP UNTIL Temp$ <> ""          ' Loop until key pressed
PRINT Temp$                     ' Print the character on screen
GetChar$ = Temp$                ' Pass the value to the main program
END FUNCTION

And in the main code:

KeyPress$ = GetChar$

Again, this drastically shortens our code and makes it easier to get a single character from the user. (Strictly, the above example is obselete as it could be substituted with the INPUT$ function) It is vital that you include the line 'FunctionName = Value' at some point in the function, otherwise the main program will recieve the value 0 or null from the function. In the example we have put GetChar$ = Temp$ to pass the value of Temp$ to the main program.

5.0 Summary
We have (hopefully) learnt that modular programming has many advantages over normal programming, the biggest being the improved readability of the source code. In reality, all there is to modular programming is deviding your program into tasks and figuring out the best way to interchange data between the modules. Modules are written in the same manner as normal QBasic programs, although some statements are illegal in modules (you'll know when you try to use them).

6.0 Closing words
I hope this tutorial has given you some ideas for structuring your programs in a functional way, modular programming really is the most important aspect of structured programming. I encourage you to use modules in your programs, as you will probably be able to use some of them again in later projects. Eventually you will have built up your own set of QBasic commands to be used over and over again, saving you precious time and letting you concentrate on the important parts of your program. Thank you for reading this tutorial.



This article originally appeared in The BASIX Fanzine Issue 15 from June 1999.