Procedures - Subroutines and Functions
In PowerBASIC, a programmer can name a block of code which can be executed by simply calling out that name. These named blocks of code are called procedures. The most commonly used procedures are subroutines and functions.

Here is a summary of the PowerBASIC functions used to create and manage procedures. These are discussed in more detail further down this page.

Declarations

And here are the allowed locations of procedure declaration statements within PowerBASIC programs. Note that the PowerBASIC compiler allows the CLASS/Sub/Function code blocks to be placed before or after the PBMain() function.

    #COMPILE EXE

    Function PBMain() As Long              'PBMain() Function
    End Function

    CLASS myClass                          
        INTERFACE myInterface
            METHOD myMethod                'Method
            END METHOD
            PROPERTY myProperty            'Property
            END PROPERTY
        END INTERFACE
    END CLASS

    SUB mySub()                            'Sub
    END SUB

    FUNCTION myFunction()                  'Function
    END FUNCTION

See the declarations tutorial for syntax and examples on using the declare statements. Usage is very straight-forward but be sure to note that when using the GLOBAL declaration on arrays, the array variables must be declared with no subscripts.

Sub and Function Examples
To aid in the discussion of these two types of procedure (Sub and Function), here is a very simple example of each.

    Function MyFunc(nVar As Long) As LONG  'nVar is argument passed to MyFunct
        nVar = nVar + 1                    'increments nVar by 1
        MyFunc = 1                         'Function return value set to 1
    End Function
    
    Sub MySub(nVar As Long)                'nVar is argument passed to MySub
        MSGBox nVar                        'nVar is shown in a MSGBox
    End Sub

Both procedure types can be given one or more values when called. In these examples, a single variable called nVar (long integer) is made available to each procedure. When the Sub/Function procedures are called, the calling source code provides nVar.

The two procedures differ in that a function can act like a variable - returning a value when the last line of the function code is executed. A subroutine (Sub) cannot return values. It simply executes the lines of code within it and returns execution to the point in source code which called the subroutine.

Calling Sub/Function Procedures
To execute a Sub simply put its name on a line of code by itself, including any needed arguments. However, a Function returns a value and is inserted into a PowerBASIC expression like any other variable. Here are some statements which show how to call the Sub/Function examples given above.

    Dim nVar As Long          'variable nVar is defined as long integer
    nVar = 5                  'nVar value set to 5
    MySub(nVar)               'executes MySub.  MSGBox displays "5"

    Dim nVar, Result As Long  'two variables defined - nVar and Result
    nVar = 5                  'nVar value set to 5
    Result = MyFunc(nVar)     'Result = 1, nVar = 6. Treats MyFunc like a variable
                              'whose value is assigned to Result

In both examples, code is shown that creates variables outside the Sub or Function. The variable nVar is passed as an argument to both procedures. In the Sub, the value of nVar is displayed. In the Function, the value of nVar is changed - both inside and outside the function.

Sub/Function Location
In a PowerBASIC source code file, Sub/Function procedures may be placed in any order. The compiler reads the entire source code before attempting to execute the PBMAIN() function, so the order in which procedures are placed in the source code file is not important.

It is common, however, for the PBMAIN() function to be placed at the top of a source code file so that a programmer can easily see the code which will be executed first.

Procedure Declaration
A Sub/Function procedure is created by simply writing the code and enclosing it with the Sub/End Sub or Function/End Function statements. The syntax for the Sub/Function statements is shown next.

[STATIC] SUB ProcName [BDECL | CDECL | SDECL] 
         [ALIAS "AliasName"] [([arguments])] 
         [EXPORT | PRIVATE] [STATIC]
    .... statements
END SUB

   Sub MySub()                 # no arguments
   Sub MySub (iVar as Long)    # one passed variable
   STATIC Sub MySub()          # variable values kept between calls
   Sub MySub ALIAS "M" ()      # simple alias name reduces typing
   Sub MySub () Export         # allows external access

[CALLBACK | THREAD] FUNCTION FuncName [BDECL | CDECL | SDECL] 
         [ALIAS "AliasName"] [([arguments])] 
         [EXPORT | PRIVATE] [AS type]
    .... statements
END FUNCTION

   Function MyFunc () AS Long      # no arguments, returns Long
   Function MyFunc (r as Integer)  # single argument, default type
   Function MyFunc () Export       # allows external access

These two procedures use mostly common arguments, although some difference exist. The arguments are discussed here.

Arguments
Not just one, but a list of values may be passed to procedures. Constants (numeric or string literals) may be passed, but it is more common to put variables in the argument list of a procedure so that the current value of the variables are received by the Sub/Function procedures. The list of arguments (values/variables) passed to a procedure consists of one or more arguments using the following syntax. The first two examples show the syntax for a single passed value. The third line of example code shows how three arguments would be passed, as a comma-separated list.

    Sub MySub (ByVal arg1 As Long)
    Sub MySub (ByRef arg1 As Single)

    Sub MySub (arg1 as Long, arg2 as Single, arg3 as String)

Each argument can carry two descriptors - the way in which the value is passed (ByVal or ByRef) and the data type (Long, Single, ...).

When the calling source code uses a variable as an argument, the programmer can determine if the procedure is allowed to change the value of the variable. Placing the ByVal keyword in front of an argument, prevents the procedure from changing the value of the argument.

Global Variables - No Argument Needed
While Sub/Function procedures can have variables/values passed to them, global variables are available to all Sub/Function procedures without having to include them in the argument list. Further, any change made to a global variable is permanent. The changed value will be seen by all source code anywhere in the PowerBASIC program.

It is common practice to avoid using Global variables. Using only local variables, those defined within a Sub/Function procedure, helps to prevent procedure code from having unintended impact on code elsewhere in the program.

If you have suggestions or corrections to this page, please let me know.