Call a function: Difference between revisions

Line 936:
D = 3 + DIST(X1 - X2,YDIFF,SQRT(ZD2)) !Invoke local function DIST.</lang>
In this case, even if "DIST" happened to be the name of some library function, invocations within the routine defining it would not be of the library function.
 
This flexibility in naming can be turned the other way around. For example, some compilers offer the intrinsic function SIND which calculates ''sine'' in degrees. Simply defining an array <code>REAL SIND(0:360)</code> (and properly initialising it) enables the slowish SIND function to be approximated by the faster indexing of an array. Put another way, an array is a function of a limited span of integer-valued arguments and is called in arithmetic expressions with the same syntax as is used for functions, be they intrinsic or user-written. Those writing in Pascal would be blocked by its insistence that arrays employ [] rather than (). Similarly, when testing, an array's declaration might be commented out and a function of that name defined, which function could check its arguments, write to a log file, note time stamps, or whatever else comes to mind. But alas, there is no "palindromic" or reverse-entry facility whereby a function could handle the assignment of a value ''to'' an array that would make this fully flexible.
 
Within a function there are some delicacies. The usual form is to assign the desired result to the name of the variable as in <code>H = A + B</code> where <code>H</code> is the name of the function. However, during evaluation the desired result might be developed over many stages and with reference to prior values. Suppose function H is to combine results from separate statements and it is not convenient to achieve this via one lengthy expression, perhaps because of conditional tests. Something like <lang Fortran> H = A + B
IF (blah) H = 3*H - 7</lang>
As written, the appearance of <code>H</code> on the right-hand side of an expression does ''not'' constitute ana invocationcall of function <code>H</code> at all. Some compilers fail to deal with this as hoped, and so one must use a scratch variable such as <code>FH</code> to develop the value, then remember to ensure that the assignment <code>H = FH</code> is executed before exiting the function, by whatever route. If the result is a large datum (a long character variable, say) this is annoying.
 
With the belated recognition of recursive possibilities (introduced by Algol in the 1960s) comes the possibility of a function invoking itself. In the above example, <code>H(3.7,5.5,6.6)</code> would clearly be a function invocation (because of the parentheses) whereas <code>H</code> would not be. Actually, Fortran routines have always been able to engage in recursion, it is just the returns that will fail - except on a stack-based system such as the Burroughs 6700 in the 1970s.
Line 968 ⟶ 970:
WRITE (6,*) "Linear=",INTG8(TRIAL,0.0,1.0, 0.01)
END</lang>
This involves a fair amount of juggling special declarations so that the compiler will make the desired assumptions that a function is being called upon, rather than the value of some variable. This is eased somewhat with F90 onwards if the MODULE protocol is used so that at least you do not have to remember to declare INTG8 as REAL. Certain library functions are not allowed as candidates for passing to INTG8 (for instance, the compiler may render them as in-line code, bypassing the protocol used for functions) and arithmetic statement functions are usually rejected, alsoas would be an array masquerading as a function. Arithmetic expressions are not allowable as possible "functions" either - how might f(x)something =like <code>sin(x) + 3*sqrt(x) + 7</code> be expressedrecognised as a function instead? As <code>INTG8(SIN + 3*SQRT + 7,''etc...''</code>? ThisUnlike isAlgol, Fortran does ''not'' offer the call-by-name facility as used in [[Jensen's_Device|Jensen's Device]], which would be something like <code>INTG8(SIN(X) + 3*SQRT(X) + 7,''etc...''</code> and would also require passing variable X. APerhaps a keyword BYNAME might be introduced one day. Until then a properly-named function must be declared and its name only be given. And of course, candidate functions must have the correct number and type of parameters, or else...
 
This works because Fortran passes parameters by reference (i.e. by giving the machine address of the entity), so that for functions, the code's entry point for the function is passed. With normal variables this means that a function (or subroutine) might modify the value of a parameter, as well as returning the function's result - and also mess with any COMMON data or other available storage, so a function EATACARD(IN) might read a line of data into a shared work area (called say ACARD) from I/O unit number IN and return ''true'', otherwise ''false'' should it hit end-of-file.
Line 977 ⟶ 979:
END TYPE MIXED
TYPE(MIXED) LOTS(12000)</lang>
One might hope to try <code>IT = BCHOP(LOTS.NAME,"Fred")</code> where BCHOP is a well-tested function for performing a binary search that should run swiftly. Alas, no. The successive values of NAME are not contiguous while BCHOP expects to receive an array of values that are contiguous - that is, with a "stride" of one. So, the compiler inserts code to copy all the LOTS.NAME elements into such a work area and passes the location of that to BCHOP (which searches it swiftly), then on return, the work area is copied back to LOTS.NAME just in case there had been a change. This latter can be avoided if within BCHOP its array is given the attribute INTENT(IN) for read-only but the incoming copy still means an effort of order N, while for the search the effort is just Log(N) only. This can have a less-than-subtle effect if large arrays are involved.
 
=={{header|Go}}==
1,220

edits