[Next] [Up] [Previous]

The USE Statement

The USE statement has the syntax

       USE environment-name,filename

where filename is optional, and is a character-valued expression. It causes the text of the named environment to be, in effect, placed in the program at the point where the USE statement was encountered, and the programs whose object code is in the environment to be callable from the program in which the USE statement is found, as well as (less usefully) from any other programs loaded into memory at the same time.

In some implementations, because ENVIRONMENTs are incompatible with the available linkage loading mechanisms, the filename may be compulsory the first time a USE statement referring to environments in a given file is encountered, but not in subroutines, even externally compiled subroutines, later in the source stream.

In FORTRAN, a subroutine can be passed as a parameter to another subroutine, using the EXTERNAL statement.

In ALGOL 68, operators, like + or *, can be passed this way as well.

However, in FALCON, the ALIAS statement means that the name of a subroutine can actually refer to several different possible subroutines, which is not true in FORTRAN. In ALGOL 68, or most other languages, including FORTRAN, + and * have the same property, since the act of adding two integers is different from the act of adding two complex floating-point numbers.

There are three basic ways that a language can avoid this problem: like FORTRAN, only pass items with a unique meaning, thus not having the problem; like APL, have only one real type of variable, a variable that comes with a flag indicating the type of its current contents; or, like PASCAL, do not allow separate compilation of modules, so that the compiler can modify how it compiles a subprogram depending on the way it is used.

FALCON does not take any of these approaches. Instead, the programmer is required to explicitly declare to the compiler how it is to choose the actual routine to pass in such circumstances.

Thus, in addition to a statement such as

       PFUN FG((REAL)X)

we can have a statement like

       PFUN FH((REAL)X,(OPERATOR) = (REAL) &.M. (REAL))

so that when a call to FH appears in the form FH(LL,+) then within FH the variable X has the value of LL (converted to REAL if needed), and M(a,b) is a function which adds two real numbers only. (Some operators may be implemented by in-line code, particularly those which perform very simple operations. Tor these operators, a 'dummy' version which is called in the same fashion as a normal external subroutine must also be provided by the implementation, so that %%S((REAL) + (REAL)) can be passed in the internal form of a subprogram address (remove one %-sign to make that the apparent form).)

Note that operators or functions can be given in an argument position declared either OPERATOR or FUNCTION; the type conversion performed is to provide the address of a subprogram which performs any necessary conversion of calling sequences before calling the subprogram given as a parameter.

Since the second argument to FH is declared to be an operator in the PFUN statement, the compiler does not attempt to treat + as the start of an expression. Also, because FALCON allows functions with the attribute NILADIC, the name of such a function could be a valid expression as well as identifying a function.

Therefore, to pass a function to an undeclared external procedure, the name must be enclosed in %%S(...) with a full specification if necessary, or by being declared a subprogram name by being mentioned in an RNAME statement, similar to FORTRAN's EXTERNAL statement (but not YAL's EXTERNAL statement), if no specification is required. (That is, if the function name is not 'overloaded', having multiple meanings depending on context.) As this indicates, the variable M in function FH above has the type SUBPROGRAM; this is a direct consequence of the FUNCTION declaration, and does not need to be declared explicitly. With external compilation, both the XFUN and FUNCTION headers would contain an FUNCTION declaration clause, as the usage (FUNCTION or SUBROUTINE), rather than just the type, of such variables must be specified.

In APL, +/A is the total of all the elements in A; this is called 'reduction', applied to the operator +, over A. A _REDUC function is built in in YAL, but showing how the user could write such a function in YAL will illustrate these YAL features effectively.

As we are dealing with an extended calling sequence, not a simple FORTRAN type sequence with all variables having a fixed data type, REDUC must be declared in the calling program:

       XFUN REDUC((OPERATOR(MUTABLE)=(MUTABLE) &.M. (MUTABLE)),
                  (MUTABLE) X)

which converts X to a form indicating its type. This is the simplest manner of making a program able to handle parameters of any type, but it may have penalties in execution-time efficiency.

This is REDUC:

       SUBROUTINE REDUC((OPERATOR(MUTABLE)=(MUTABLE) &.M. (MUTABLE)),
                  (MUTABLE) X)
       . J=&DIM X
       . REDUC=X(1)
     7 FOR I=2,J
       . REDUC=REDUC &.M. X(I)
       REPEAT 7
       RETURN

Note that this simplified example makes no provision for handling multi-dimensional arrays, or arrays with non-standard indices.

If a function, rather than an operator, is given as the argument of REDUC, implicit type conversion to a function-derived operator (&:fname: or &:fname:.(...)) is performed; that is, the address of a routine calling the function and performing the necessary calling sequence conversions is passed if that is required by the implementation.

Another part of the reason that REDUC is declared in the calling program is a factor that should be clearly understood by programmers: that MUTABLE variables, when passed as arguments, are not compatible with other types, as explained at the start of the section on subroutines.


[Next] [Up] [Previous]