[Next] [Up/Previous]

The ALIAS Statement

The ALIAS statement has the basic form

       ALIAS call1 ?; call2
and provides, in a sense, a macro facility, but one only applicable to function and subroutine calls. Since this facility is directly oriented to the language, however, it can do things that cannot be done by giving instructions to replace one character string in the program text by another. Functions can be replaced by in-line code, and the replacement for a function name can be (and indeed, often will be) determined by the types of its arguments.

A simple ALIAS statement might be

       ALIAS (FUNCTION) SKV(M,N) ?; VQQ(N,M)

which would have the effect of taking any statements like

       . B=SKV(25,E)

in the program and changing them to

       . B=VQQ(E,25)

in terms of their results.

For an operator, the syntax would be

       ALIAS (OPERATOR) = K &.DTR. L ?; L &.DZX. K

Note that, in the absence of a declaration to the contrary, it is assumed that both sides of the meta- separator ( ?; ) have the same type of entity present. Thus, changing from a function to an operator is possible with a statement like

       ALIAS (FUNCTION) VTK(R,L) ?; (OPERATOR) = L &.VTS. R

and the reverse change is equally possible (instead of using &:...: , which accomplishes the same change by syntactic means).

A program can contain multiple ALIAS statements referring to a single function name, provided that there is some way of determining which one applies, for example, by the number or type of the arguments. Thus, the following statements

       ALIAS (FUNCTION) SIN((REAL)X) ?; (REAL) SIN(X)
       ALIAS (FUNCTION) SIN((DOUBLE)X) ?; (DOUBLE) DSIN(X)
       ALIAS (FUNCTION) SIN((QUAD)X) ?; (QUAD) QSIN(X)
       ALIAS (FUNCTION) SIN((COMPLEX)X) ?; (COMPLEX) CSIN(X)
       ALIAS (FUNCTION) SIN((DCX)X) ?; (DCX) CDSIN(X)
       ALIAS (FUNCTION) SIN((QCX)X) ?; (QCX) CQSIN(X)

create a function that behaves like _SIN for the types supported in FORTRAN from the sine functions available in FORTRAN, including the sine functions for types in extended versions of FORTRAN IV. (Since QSIN is used for quad precision, single precision quaternion sine might have to be QASIN, for a FORTRAN extended to all the floating-point types of FALCON. However, while QARSIN is quad precision arc sine, an ambiguity does exist in trying to name the TAN function's relatives.)

The type specifier applied to the dummy argument appears on the left side of the meta-separator (?;), as it is used to distinguish which ALIAS statement to use. The FUNCTION specifier also appears there, as it is also a characteristic of the way SIN will be used in the program.

The type specifier of the function itself, however, appears on the right side of the meta-separator. Thus, an expression such as

       I+SIN(V)

will not cause the computer to reject the above ALIAS statements because an integer result from SIN appears to be called for. Instead, (I being INTEGER, V being REAL) the first ALIAS statement will be applied, and then the fact that the result of SIN is REAL will be used to determine the appropriate type conversion (I from INTEGER to REAL) to take place before the addition operator is executed.

While using function result type to distinguish between ALIAS statements is possible, the consequences are not always predictable, so it is not recommended.

Using a type specifier on the right side of the first meta-separator for a dummy argument allows the desired implicit type conversion to be specified.

The ALIAS statements above do not prevent the use of SIN(I) in an expression, as I, of integer type, is converted to the lowest suitable type available following the implicit conversion rules used for built-in functions. These rules are also available in the case of multiple argument functions when, for example, all available aliases have their arguments all declared to be of the same type.

A situation like

       ALIAS (FUNCTION) UU((INTEGER) A1, (REAL) A2) ?; (REAL) U1(A1,A2)
       ALIAS (FUNCTION) UU((REAL) A1, (INTEGER) A2) ?; (REAL) U2(A1,A2)

followed by a call to UU(I,J) where I and J are both INTEGER, however, will not necessarily be resolved in any consistent manner by FALCON. Nor is there any relative scale in which the difference between the NUMERIC and INTEGER types can be compared to the difference between the REAL and QUAD_QUATERNION types.

An ALIAS statement can also place extra parameters in a function call: for example,

       ALIAS (FUNCTION) RJL(X) ?; RAJL(X,%(2))
       ALIAS (FUNCTION) RPL(X) ?; RAJL(X,%(1))

creates two special cases of the RAJL function: wherever RJL(N) appears in an expression, it is replaced by RAJL(N,2). The parentheses preceded by a percent sign are not strictly necessary in the example above: however, as ordinary parentheses are used to indicate type specifications, an expression like (X+Y)*2 does need to be so surrounded. Also, the percent sign with parentheses is always needed for constants on the left side of the meta- separator, since on that side dummy variables are created. Such constants can be used in this way:

       ALIAS (OPERATOR) = %(0) &.CIRC. X ?; (=) _SQR(1-X*X)
       ALIAS (OPERATOR) = %(1) &.CIRC. X ?; (=) _SIN(X)
       ALIAS (OPERATOR) = %(2) &.CIRC. X ?; (=) _COS(X)

which begins an attempt to define an operator for use in FALCON that behaves like the APL circle operator. Note that system functions are being used on the right-hand side of the meta-separator. The equals sign in parentheses immediately following the meta-separator, indicates that an expression is being substituted, just as (OPERATOR) would indicate that an operator is being converted.

The following ALIAS statement

       ALIAS (FUNCTION) F1(X) ?; F2((REAL) X, (INTEGER) X)

allows two different forms of the parameter of F1 to be passed to F2. Use of this with the TEXT, SEQUENCE, and EXPRESSION declarations can be quite powerful.

The %(...) construct can be used within expressions in this context as well; for example,

       ALIAS (FUNCTION) XYL(X) ?; (=) 3*VTX(%((REAL) X))

specifies that X is to be converted to REAL in calling VTX. Normally, this would instead be specified when VTX is declared, so this is not a common use of %(...). Note that this is the reverse of the usual use of %(...); allowing a non-expression using expression symbols within an expression, instead of allowing an expression within a clause which uses symbols found in expressions for other purposes.

A type declaration can appear between the ?; and the = to specify a type conversion for the result of the expression, since a variable type (unlike a routine type: FUNCTION versus SUBROUTINE) does not affect the syntax of what follows.

A FUNCTION can easily be used to create a SUBROUTINE by means of the ALIAS statement:

       ALIAS (SUBROUTINE) CCX(X,Y,Z) ?; (.FUNCTION) Z=CDL(X,Y)

causes

       CALL CCX(A,B,C)

to be equivalent to

       . C=CDL(A,B)

Since a SUBROUTINE was on the left-hand side of the meta-separator, and a FUNCTION on the right-hand side, something had to be done to the result of the function. The header-type . accompanied the subprogram type FUNCTION to indicate that the header would have the form of an assignment statement, causing the function result to be given to a dummy variable. (Using CCX(X,Y,CDL) on the left-hand side instead is not valid.) Although the period (.) represents a header type, it does not need to be separated from other type-specifications by a comma, provided that it appears first in a parenthesized list. (.,FUNCTION) and (FUNCTION,.) could also have been used.

If an expression were used, then we get

       ALIAS (SUBROUTINE) CCL(X,Y,Z) ?; (.=) Z = X+VZL(Y)

with the = added to expression syntax.

Causing the use of a function or an operator to actually invoke a subroutine is also possible. For example,

       ALIAS (OPERATOR) = A &.TZ. B ?; (SUBROUTINE) VLM(A,B,M) ?; (=) M

causes A &.TZ. B to be replaced by a call to VLM(A,B,M); then, another meta-separator is used to indicate the clause containing the result, in this case, the expression M, with (=) indicating that it is, indeed, an expression.

Note that a function could have followed the second meta-separator: thus, for example,

       ALIAS (FN) VLZ(A,B,C) ?; (SUB) SETC(C) ?; (FN) VLR(A,B)

with FUNCTION abbreviated FN and SUBROUTINE as SUB, causes a call to VLZ to be replaced by successive calls to SETC and VLR. If SETC and VLR were entry points to the same routine, the subroutine SETC setting up the value of a usually seldom-changed parameter C, this would create the general form of the function performed by VLR.

The meta-separator ?; , since it is a separator of sorts, may also be followed by an end-of-record without ending a statement.

The first meta-separator can be @-commented as @AS?; , and subsequent ones as @AND?; . &'AS' is available as a substitute for the first meta-separator.

Thus, any number of subprogram calls can be substituted for a single subprogram call by an ALIAS statement. If it were not for the . header type specification, it would not be possible to determine which call provides the function result: as an equals sign "=" functions as a relational operator within expressions as well, the presence of an equals sign does not distinguish between expressions and assignments.

In addition to (=), which indicates that an expression, rather than a call, is to be given an alias, the option (*) is available, which indicates that a sequence is to be given an alias.

The function _IF(logical-expression,res-true,res-false) can be implemented using this modifier as follows:

       ALIAS (FN,MUTABLE) IF((LOGICAL) L,A,B) ?; 
              (*) {IF L,{. IF=A},{. IF=B}}

which correctly does not attempt to evaluate the unused argument. This is an example of implementing a function by means of in-line code.

In addition to arguments of type ALTERNATIVE, subroutines (and also functions, which cannot have arguments of type ALTERNATIVE) can have arguments of type SEQUENCE. Just as TEXT creates an actual argument of type CHARACTER, SEQUENCE creates an argument of type SUBROUTINE, or, more precisely, SUPROGRAM(SUBROUTINE).

Also, instead of the result of an expression being passed to a subroutine in the calling sequence of which it appears, the expression itself can be passed as SUBPROGRAM(FUNCTION) (where the FUNCTION is NILADIC) if that position in the calling sequence is declared of type EXPRESSION.

       ALIAS (FUNCTION) DERIV(A,B) ?; 
             DERIV2((TEXT) A,(EXPRESSION) A,(VLIST_GEN) A,
             (TEXT) B,(MUTABLE) B)

allows the function DERIV2 to calculate the derivative of A with respect to B, analytically if possible, or, if necessary, numerically, without incurring the inefficiency of calling _EXEV in the numerical case. (To allow the value of B to be changed within the routine DERIV2, the statement FREEZE B would be required somewhere within DERIV2 (provided that B is the name used within DERIV2 for its fifth argument, and that MUTABLE variables are assigned by pointer where possible), or the actual argument variable could be located by use of the third argument, provided it actually occurs in the expression.)

A built-in subprogram, that is, one whose name begins with an underscore, can appear on the left-hand side of the first meta-separator in an ALIAS statement. Even single character operators can be so modified, for example:

       ALIAS (OPERATOR) = (COMPLEX) M + (COMPLEX) N ?;
             (FUNCTION) CXADD(M,N)

is a legal FALCON statement. This allows extending the built-in operators and functions in FALCON to new operand types, to improve program readability. This capability can, of course, be abused to destroy program readability as well.

ALIAS statements can create SUBROUTINEs having the same names as existing FUNCTIONs, just as this can result from PSUB and PFUN statements (but not XSUB and XFUN statements under most operating systems). As it is subroutines that are usable as functions on the left-hand side of an assignment statement, this allows the very necessary step of writing different code to change a value from the code required to obtain the value.

Unused &word and _word items can also be created with the ALIAS statement; special characters not used in FALCON (only open single quote in standard ASCII is unused) can be defined as well. If the programmer does this, there is a risk of losing access within the program to predefined entities which the programmer did not know about anyways. Since the explicit declaration takes precedence, it is only a weak violation of the NO RESERVED WORD principle; a strong one would be if an undeclared entity did not have its usual meaning because its name was a reserved word. Unlike variables, user types must be declared prior to use, since there is no possible default which would make sense.

The ability to redefine basic arithmetic operators in FALCON makes sense when it is realized that FALCON allows user-defined variable types. (In fact, this capability is a well-known feature that has been offered in other languages for some time, and is known as operator overloading.)


[Next] [Up/Previous]