Compiler enhancement (compiler edit 653): Subroutines, both internal and SBX, may now use named parameters as described above for functions and procedures. Parameter passing to subroutines is nearly identical to that for procedures and functions, so the implementation details are nearly the same as previously described. The main difference is that since subroutines do not have definition statements like functions and procedures do, a new statement had been introduced to allow you to define their parameter names and default values:
DEFXCALL xcallname{+|,}pname{|alias}{=defval},pname{|alias}{=defval}...
DEFXCALL works similarly to FUNCTION and PROCEDURE definition statements, defining the names of the parameters, their order, and optionally default values. But there are several subtle differences, noted below:
• | Unlike functions and procedures, subroutine names are not case sensitive, so neither is the DEFXCALL statement. This applies to the subroutine name and the parameter names, but not to the default values. The following two statements are therefore equivalent: |
DEFXCALL MSGBOX,MSG,TITLE="Warning",FLAGS
defxcall msgbox,msg,title="Warning",flags
• | Immediately following the xcall name, you can use a "+" instead of a "," to create a definition specific not just to the xcall name but to the combination of the xcall name with a literal string or numeric first parameter. This is particularly useful with some built-in subroutines like AUI and MIAMEX which have completely different syntax and semantics depending on the first parameter. For example: |
DEFXCALL AUI+AUI_ENVIRONMENT,opcode,guiflags
DEFXCALL AUI+AUI_EVENTWAIT,parentid,ctlid,exitcode,opflags,timer
DEFXCALL MIAMEX+MX_FSPEC,spec,locpath,ext,flags,ddb,status
• | You may define a single alias (alternate name) for any of the parameters. This is useful in cases where documentation or usage evolution has resulted in a parameter having more than one common name. For example, to allow the first parameter to AUI_ENVIRONMENT to be called either opcode or opflags, we could define it as: |
DEFXCALL AUI+AUI_EVIRONMENT,opcode|opflags,guiflags
• | As with function and procedure definitions, you can define default values for any parameters, and doing so converts all of the other parameters (those without defaults) to mandatory status. However, there are many existing internal subroutines which have a large number of optional parameters, making both named parameters and defaults extremely useful, which may determine semantics based on the number of passed parameters. |
To better align the declarative capabilities of DEFXCALL with the ways in which existing subroutines may have been implemented (hidden from view in most cases), another difference is that DEFXCALL supports an option to separate the parameter list into an initial mandatory group and a trailing optional group by enclosing the trailing optional group in {squiggly brackets}. For example:
DEFXCALL TEST1,one,two{,three,four,five}
Note that the {brackets} cannot be nested.
In the above example, we are indicating that the last three parameters are optional, which has these important semantic side-effects:
• | it makes the first three parameters truly mandatory, even if no default values are defined |
• | for the parameters in the optional section, even those with defaults |
• | defined will be ignored unless the caller specifies one or more parameters beyond that one. |
A few examples will help clarify this:
DEFXCALL TEST1,one,two,three,four,five
DEFXCALL TEST2,one,two=2,three,four,five
DEFXCALL TEST3,one,two=2{,three=3,four,five=5}
DEFXCALL TEST4,one,two{,three=3,four=4,five}
All four routines have five defined parameters, but the semantics and requirements are different in each case.
TEST1's parameters are all optional, because no defaults were specified, nor were {brackets} used to identify an optional section.
TEST2's parameters are all mandatory, because there is at least one default defined, yet no {brackets} to mark the optional parameters.
TEST3 has two mandatory parameters (one and two), and three optional parameters. The default specified for parameter two has no effect, since the parameter being prior to the start of the {optional} parameters, must be explicitly specified by the caller. The caller can specify 2, 3, 4, or 5 parameters (or more), but if parameter five is specified by name, then parameter four must also must also be specified, since it has no default and gaps are not allowed, even within the optional set of parameters. The default value for parameter five has no effect, since the parameters within the {optional} list are only passed to the routine up to the highest numbered parameter that is actually specified in the call.
TEST4 is a more logical version of TEST3 in that it eliminates the two default values that had no effect in TEST3 (two=2 and five=5), and adds one that might be useful (four=4). The following call:
XCALL TEST4,100,200,FIVE=500
would be considered legal—the two skipped parameters have defined defaults—and would be converted the equivalent of:
XCALL TEST4,100,200,3,4,500
WARNING: Because the semantics of the DEFXCALL statement are somewhat tricky, and because this is all quite new, pioneer developers are invited to experiment with it, particularly with their own SBX calls, but should probably delay using it heavily (especially with subroutines internal to A-Shell) until it has had a bit more field exercise. At the very least, it will make more sense for MicroSabio to release a standard set of DEFXCALL statements for internal/documented subroutines to avoid divergence in the way these common routines are used by different developers.