Updated and REview August 2011
Syntax:
FUNCTION FN'name(var1 {as <typsiz>{:<dir>}},...varN {as <typsiz>{:<dir>}} ) {as <typsiz>}
<optional local MAP statements, with optional STATIC prefix>
<optional XGETARGs>
<nearly any kind of statements>
FN'name = <expression> ! set return value
ENDFUNCTION
The function definition, as shown above, starts with a declaration of the formal parameters, their types, and return type of the function. The function name must start with "FN", "Fn", or "fn" (so that references to the function elsewhere in the program can be easily identified by the compiler as functions rather than arrays). The names of functions which return string or unformatted values must end with "$" (e.g. "FUNCTION FN'TEST$ ...); otherwise they are considered numeric functions.
The <typsiz> (data type and size) specification is similar to that used in MAP statements, except without a comma between the type code and the size. For example:
FUNCTION Fn'Test(var1 as S10, var2 as f6, var3 as B2, var4 As x256) AS i2
Function fn'display'name$(cus as ST_CUS_REC) as s MAX_NAME
The first example above illustrates that the "function" keyword and as <typsiz> clauses are not case sensitive. (The function name, and the names of the formal parameters are case sensitive.)
The second example above illustrates two useful variations of the as <typsiz> clause. The first is replace <typsiz> with the name of a defined structure (i.e. "as ST_CUS_REC"). (See Defined Structures).
The second as <typsiz> variation is the ability to replace the parameter size with a (previously defined) symbol (i.e. "as s MAX_CUSID"). Note that in this case, a single space is required between the variable type ("s") and the symbol name ("MAX_CUSID"). Using a symbol rather than a hard-coded number is useful for avoiding a common bug that may happen when passing string arguments to functions, where you decide to increase the size of the string field elsewhere in the application but forget about the function, resulting in the value being truncated within the function. (Another way to avoid the truncation bug just described is to use Dynamically-Sized S and X Variables within the function.)
Note that the use of a symbol in place of the size requires compiler edit 434, which was introduced with A-Shell version 5.1.1146.1.
See the Examples for a quick look at a couple of real functions, and see the subtopics for detailed information.
The optional :<dir> clause may be used to limit the directionality of the parameter to inputonly or outputonly, for the purpose of clarification and/or optimization. For example:
FUNCTION FN'TEST(P1 AS S20:INPUTONLY, P2 AS ST_PHONE:OUTPUTONLY)
The INPUTONLY clause serves primarily as an aid to self-documenting code, but will also cause the compiler to generate an error if you explicitly reference the parameter in an XPUTARG statement (using a literal parameter number). (There is no run-time aspect of this feature, so you won't be stopped from outputting to the parameter using a variable to specify the parameter number in the XPUTARG statement.)
The OUTPUTONLY clause also aids in self-documenting your code, but in addition it skips the input parameter binding operation (which, for very large parameters could save a lot of CPU cycles).
Subtopics