From: burley@apple-gunkies.gnu.ai.mit.edu (Craig Burley)
Newsgroups: comp.lang.fortran
Subject: SUMMARY: CHARACTER FUNCTION as dummy argument
Date: 15 Dec 92 04:48:25
Organization: Free Software Foundation 545 Tech Square Cambridge, MA 02139
NNTP-Posting-Host: apple-gunkies.gnu.ai.mit.edu

Okay, I'll take a shot at summarizing what we've learned from this
thread.  I might get things wrong, so stay on your toes, you
standards experts!  :-)  Also, I haven't kept track of who has contributed
what to this discussion as I should have -- very little of it
is original with me, and most of that is clearly stated as my
opinion anyway.  (I did come up with the problem shown in Sample 6,
however, whereby the length of a return value is never established,
and pointed out the inefficiency of the VAX/VMS FORTRAN extension to
support Sample 1, for what that's worth.)

First off, the specific situation being addressed is this:

C Sample 1:
	SUBROUTINE X(CFUNC)
	CHARACTER*(*) CFUNC
	EXTERNAL CFUNC
C (EXTERNAL is optional since there's a reference to CFUNC next.)
	PRINT *, CFUNC()
	END

To make sure we're on the same page, what is happening here is this:
presumably some program unit in the program calls X, passing in the
first argument a CHARACTER FUNCTION external procedure (or, I suppose,
an intrinsic; CHAR is the only one available in ANSI FORTRAN 77, but
it is not standard-conforming to pass it as an actual argument
[see 15-3 38-45]).  X declares no length for the procedure via the *(*)
construct, then references the procedure.

Because X both references the CFUNC procedure and declares it as *(*),
X is _not_ a standard-conforming program unit in Sample 1 [15-2 5-7].

The following two Samples are, however, standard-conforming (and GNU
Fortran, currently in alpha test, will accept them as soon as I change
it to do so -- thanks folks for getting me to try this out! :-):

C Sample 2
	CHARACTER*(*) CFUNC
	EXTERNAL CFUNC
	CALL Y(CFUNC)
	END

C Sample 3
	SUBROUTINE Y(CFUNC)
	CHARACTER*(*) CFUNC
	EXTERNAL CFUNC
	CALL X(CFUNC)
	END

The reason both of the above Samples are standard-conforming is that
they do not contain _references_ to CFUNC, so even though CFUNC is
clearly a procedure, [15-2 5-7] is not violated.  Only a program unit
that actually _references_ a CHARACTER FUNCTION must declare it via
CHARACTER*n, where n is an integer constant expression.

Now, it is _possible_ to extend the language to permit Sample 1, and
VAX/VMS FORTRAN does so.  However, doing so affects (negatively) the
performance of standard-conforming code, because the return length of
any CHARACTER FUNCTION (not just *(*) ones) must be passed along with
the function in case the ultimate caller (the program unit doing the
reference) declares the procedure with *(*) instead of *n.  In
my opinion, extensions that even slightly reduce the performance of
programs that don't use them are not wise as a default.  (So if I add
the extension to GNU Fortran, which seems hard-to-impossible while it
uses f2c-compatible calling sequences by the way, I'll add it so it has
to be turned on via a command-line option when compiling _all_ related
source files.  Hardly seems worth it, and see below for more problems with
this kind of extension.)

As to the why's and wherefores:

ANSI FORTRAN 77 is set up so dynamic allocation is _never_ required by
a standard-conforming program, either via heap or stack allocation.

When a compiler sees code like this:

C Sample 4
	CHARACTER*10 CFUNC
	PRINT *, CFUNC()
	END

The compiler knows it need only allocate, statically at compile time,
10 characters of memory to hold the value returned by CFUNC.  In fact,
generally, in a static-allocation model, it is always the _caller_ of
a function that allocates (statically) space for the return value.  The
callee can't allocate it statically because it can't know how many
outstanding return values must be maintained before they are no longer
needed by the caller, as in:

C Sample 5
	CHARACTER*10 CFUNC
	CALL FOO (CFUNC(), CFUNC())
	END

If CFUNC was responsible for allocating space for its own return value,
and that allocation was done statically, then the second invocation of
CFUNC would overwrite the first (no matter the order of invocation) and
FOO would see two identical results even though CFUNC might return
different values each time.

So, if the _caller_ has to allocate static space for the return value,
which is indeed the case, it must know how much space to allocate.

Going back to Sample 1, which is repeated here,

C Sample 1:
	SUBROUTINE X(CFUNC)
	CHARACTER*(*) CFUNC
	EXTERNAL CFUNC
C (EXTERNAL is optional since there's a reference to CFUNC next.)
	PRINT *, CFUNC()
	END

the caller of CFUNC, X, does not know how much space to allocate for
CFUNC's return value.

So, how does VAX/VMS FORTRAN support code like in Sample 1?  Apparently,
it resorts to dynamic allocation in this case, but apparently it _also_
relies on the caller of X having declared CFUNC as *n, not *(*) (which,
as demonstrated in Samples 2 and 3, would be standard-conforming),
and mandates that all CHARACTER FUNCTION arguments are passed along with
info on their declared length.  The latter aspect is, as I said above,
troubling because it has to be done even for programs that don't use this
extension, and because it seems possible (unless documented as unsupported)
to have a reference to a CHARACTER*(*) FUNCTION that contains _no_
information on the length of the return value.  The former aspect is simply
an extension used when necessary, but something that goes outside the
bounds of typical ANSI FORTRAN 77 implementations.

Now, one might point out that dynamic allocation could be avoided in
Sample 1 by insisting that the caller of X (the "ancestor caller" of
CFUNC) not only pass the return length of CFUNC but also pass a statically
allocated place to store the return value of CFUNC.  However, this would
introduce two problems:

    1.	Replacing PRINT *, CFUNC() with CALL FOO (CFUNC(), CFUNC())
	would result in the same problem illustrated in Sample 5, whereby
	the place provided by the ancestor caller of CFUNC to be written
	by the first invocation of CFUNC would be overwritten by the second
	invocation before calling FOO, so FOO would see two arguments with
	the same value instead of two different values.

    2.  If the ancestor caller of CFUNC declared CFUNC as CHARACTER*(*) and
	EXTERNAL before passing it it to X, which as shown in Samples 2 and
	3 would be standard-conforming, then the ancestor caller _couldn't_
	statically allocate space for X, and then if X itself was declared
	CHARACTER*(*), _no_ code in the entire program unit would declare the
	actual length of the return value of CFUNC!  (This is the problem that
	VAX/VMS FORTRAN might have right now, as noted above; I think the
	only way to handle it might be to "crash" at run time when an attempt
	is made to invoke a function declared CHARACTER*(*) for which the
	length is not known by the ancestor caller.)

So, once again we return to the simple requirement of a static-allocation
strategy: the _caller_ is responsible for allocating space for the return
value of a function, and therefore must know how much space to allocate
at compile time.  That way, CALL FOO (CFUNC(), CFUNC()) is handled
simply by allocating space for _two_ return values, each of which is
10 characters long (given CHARACTER*10 CFUNC).

If anyone has a system that supports the code in Sample 1 (like VAX/VMS
FORTRAN), it'd be interesting to see how well it handled the following:

C Sample 6
	CHARACTER*(*) CFUNC
	EXTERNAL CFUNC
	CALL X (CFUNC)
	PRINT *, 'Done!'
	END
C
	SUBROUTINE X (CFUNC)
	CHARACTER*(*) CFUNC
	EXTERNAL CFUNC
	PRINT *, 'Try this:'
	PRINT *, CFUNC()
	PRINT *, 'Now try this:'
	CALL Y (CFUNC(), CFUNC())
	END
C
	SUBROUTINE Y (ARG1, ARG2)
	CHARACTER*(*) ARG1, ARG2
	PRINT *, ARG1(1:10), LEN (ARG1)
	PRINT *, ARG2(1:10), LEN (ARG2)
	END
C
	CHARACTER*(*) FUNCTION CFUNC ()
	INTEGER I,J
	CHARACTER C
	SAVE I,C
	DATA I/50/, C/'A'/
	DO 10 J = 1, I
	   CFUNC(J:J) = C
10	CONTINUE
	I = 2 * I
	C = CHAR (ICHAR (C) + 1)
	END

It _should_ print something like this:

    Try this:
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
    Now try this:
    BBBBBBBBBB      100
    CCCCCCCCCC      200
    Done!

Or, maybe the BB... and CC... lines would be reversed, depending on how
the compiler orders the calls to CFUNC in the CALL Y statement.

However, I can't imagine any implementation getting that "right", whatever
right means.  The interesting info is just _how_ various implementations
fail.  I claim that the only generally useful implementation is one that
fails when compiling X by complaining that CFUNC cannot be both a CHARACTER*(*)
FUNCTION and referenced, and that an implementation that extends the
language so it doesn't complain so is making standard-conforming programs
unecessarily inefficient and perhaps introducing other problems like
the one shown above.

Hmm, maybe this isn't much of a summary after all!  :-)
--

James Craig Burley, Software Craftsperson    burley@gnu.ai.mit.edu
Member of the League for Programming Freedom (LPF) lpf@uunet.uu.net
Newsgroups: comp.lang.fortran