User-defined functions

User-defined functions (FN) work like the built-in functions — ABS(n), MOD(a,b), LEFT\$(a\$,n), and so on — except that you define what the function does. Defining new FN functions is something like extending the definition of the BASIC language. The FN function contains code that can be called from several places in the program, each time returning to the place from which it was called on that occasion. (The GOSUB is another way to write code to be called from multiple places.)

Here is an example of a user-defined function that takes a single numeric parameter and simply returns a numeric value that is twice the value:

FN.DEF Double(A)
FN.RTN A*2
FN.END

If you write Double(5) anywhere else in your program, this function would refer to 5 as A and return the value 10. That code in your program would work just as though you had written 10 there.

Location. An FN function must be defined earlier in the program than any of the places that call it. Generally, a program consists of all the FN functions, followed by the main program.

Nesting/recursion. An FN function can call another FN function, and can even call itself, or call other functions that call it.

Return value. Every FN function returns a numeric or string value, which can be used as though the value replaced that use of the FN function. For example, you can code an FN function instead of a value supplied to a BASIC statement, in order to use a computed rather than a constant value. You can assign the return value to a variable. You can use an FN function in an expression, to combine the return value with other quantities. Continuing the above example that defined a function Double, this code prints the value of 2E + 5:

PRINT Double(E)+5

You can use the name of an FN function as a BASIC statement of its own. In that case, the function's defined behavior is executed but its return value is not used. In such cases where the return value is unimportant, you can precede the function with the keyword CALL. The following would compute the value 24 but do nothing with it.

CALL Double(12)

Name. When defining an FN function, you specify its name. The rules for naming FN functions are the same as for naming variables. If the function's return value will be a string, its name must end in \$. Otherwise, the return value will be numeric.

The formatter capitalizes the names of built-in functions, but does not capitalize the names of user-defined functions. Use of lowercase letters is an easy way to indicate that a function is user-defined with FN.

A single program must not define the same FN function more than once.

You can give an FN function the same name as a built-in function.

• If you redefine a built-in numeric function, your function overrides the built-in definition. For example, you are free to provide your own definition of MOD(). In this case, your MOD() is called instead of the built-in MOD(), and there is no way to gain access to the built-in function.
• If you redefine a built-in string function, your function definition is treated as valid but never takes effect. For example, USING\$() continues to reach the built-in function even if you write a different function. This is because BASIC evaluates numeric expressions and string expressions differently.

Parameters

Parameters let an FN function communicate with the code that calls it. Each parameter is one of the following

1. A numeric scalar, such as N
2. A string scalar, such as T\$
3. A numeric array, such as A[]
4. A string array, such as text\$[]

The parameters in the function definition correspond to the parameters in each location that calls the function, by their sequence inside the parentheses. The type of parameter in each call must be the type that the function expects. For instance, if the 2nd parameter in the function's definition is a numeric scalar, then in every call to that function, the 2nd parameter must be a numeric scalar (which can be a constant or an expression).

Parameters let the caller pass values to the function. Parameters let the function pass values back to the caller only in the following cases:

• The parameter is an array, or
• The caller passes the name of a scalar variable and precedes it with the symbol &.

In these two cases, the function can change the variable and the caller will receive the changed value in the scalar variable that it passed to the function. (In these cases, parameters are "passed by reference" rather than "passed by value.") The return value is another method for a function to pass a value back to the caller.

If a function has no parameters, the parentheses must be present, both when defining and when calling the function.

Variable scope

With two exceptions noted below, all variables a user-defined function creates are private to it. If you write an FN function that creates a variable V\$, then this variable:

• Is unrelated to any V\$ defined outside the function, and
• Is unrelated to V\$ during any previous call to the same function.

That is, the scope of a variable in an FN function is that single call to that single function. When the function returns, all its variables are discarded and the memory they used is reclaimed.

If your FN function creates a variable V\$ and calls itself, then the inner function cannot obtain or modify the V\$ value set by the outer one. If the inner function creates a variable V\$, it will be a new, independent variable.

Data structures

BASIC data structures that programs use with a numeric pointer — such as lists, stacks, bundles, bitmaps, and graphical objects — are global to the BASIC program. If an FN function executes LET P=4, then P survives only until the function returns. But bundle number 4 is the same as it is throughout the BASIC program. So FN functions can read and modify all these data structures.

Interrupt routines

Interrupt routines have access to the global symbol table. When an interrupt routine calls an FN function, that function also has access to variables defined outside it. This is an exception to the general rule, and is a source of programming errors that are difficult to locate. If you define a function that creates a variable I, then if called from an interrupt routine, creating that variable might change the value of a variable named I that had been created in the mainline.

FN.DEF

Begins the definition of a user-defined function

Synopsis
FN.DEF name|name\$( {nvar}|{svar}|array[]|array\$[], ... )
Description

FN.DEF begins the definition of a function. Following FN.DEF is the desired name of the function. If the return value will be a string, then give the function a string name, by appending \$. If the return value will be numeric, omit the \$.

If the function takes parameters, list the names by which they will be known within the function, surrounded by parentheses and separated by commas. Each parameter can be numeric or string; it can be a scalar (single value) or an array.

You must end the definition of the function, using FN.END, before using FN.DEF again to define another function. Although execution can be nested (the body of one FN function can call others), definitions cannot be nested.

Examples
FN.DEF cut\$(a\$, left, right)
FN.DEF sum(a, b, c, d, e, f, g, h, i, j)
FN.DEF sort(v\$[], direction)
FN.DEF pi()

These are examples of single FN.DEF statements, not of complete function definitions. It is illegal for the four examples to actually occur in sequence: This would start the definition of four functions without completing any of them. The final example is a redefinition of a built-in function, in case you really need to change the value of PI().

FN.RTN

Returns from a user-defined function

Synopsis
FN.RTN <sexp>|<nexp>
Description

FN.RTN specifies the return value (see the introduction) that the function returns to its caller. If FN.DEF defined a string function (if the function's name ended in \$), then FN.RTN must be followed by an sexp. If FN.DEF defined a numeric function, then FN.RTN must be followed by an nexp. FN.RTN must provide a return value; the caller does not have to do anything with it. (See, for example, CALL.)

Parameters passed by reference are another way for a function to return data to its caller.

A function cannot return a data structure, such as a bundle, but it can return a number meant to be used as the pointer of a bundle.

As well as indicating the return value, FN.RTN performs an immediate transfer of control to the caller. There can be as many FN.RTN statements as desired inside a function (such as in an IF statement) and no code following FN.RTN is reached on that call to the function.

Example

The following function is comparable to the built-in MAX() function:

FN.DEF Bigger(A,B)
IF A > B THEN FN.RTN A
FN.RTN B
FN.END

The immediate return of FN.RTN to the caller means there is no need to use the keyword ELSE.

FN.END

Marks the lexical end of a user-defined function

Synopsis
FN.END
Description

FN.END is a lexical marker: The code of a user-defined function starts with FN.DEF and ends with FN.END. These keywords must be used in pairs.

If execution of a function reaches FN.END, it does the same thing as FN.RTN using a default value:

• Numeric functions return the value 0.0.
• String functions return the empty string ("").

CALL

Calls a user-defined function but discards its return value

Synopsis
CALL <user-defined-function>
Description

The CALL statement calls a user-defined function. If the function returns a value, it is not used; to use a return value, do not use CALL but just include the function call in an expression or BASIC statement.

Like LET, the keyword CALL can be omitted. However, including CALL leads to slightly faster execution. In addition, you must use CALL if the start of the name of the function is the same as a BASIC keyword. For example, the Format function might modify its parameter but not return a useful value. You could call it like this:

CALL Format(&A\$)

However, omitting the keyword CALL would make the interpreter read this function name as the start of a FOR statement.

Future directions

Inability of an FN function to gain access to global variables (such as screen geometry or operating modes) is a problem that private versions of BASIC have resolved in different ways. See the sidebar above.

Sources

Manual contents (Statement index)
Language features ArraysData structuresInterrupt routinesUser-defined functions
Interfaces Audio playerBluetoothGraphicsHTMLSocketsSQL
Programming notes Coexisting with Android