From: shepard@sampson.ccsf.caltech.edu (Ron Shepard)
Newsgroups: comp.lang.fortran
Subject: Re: function name as an argument
Date: 11 Dec 1992 18:05:10 GMT
Organization: California Institute of Technology, Pasadena
NNTP-Posting-Host: sampson.ccsf.caltech.edu

mroussel@alchemy.chem.utoronto.ca writes:
>In article <BURLEY.92Dec8185030@apple-gunkies.gnu.ai.mit.edu>
>burley@apple-gunkies.gnu.ai.mit.edu (Craig Burley) writes:
>>In article <1992Dec8.140008.20523@e2big.mko.dec.com> lionel@quark.enet.dec.com
>>(Steve Lionel) writes:
>>   Typically, the argument passed is the address of the routine's entry point.
>>   If the argument has CHARACTER datatype, the length is also passed by some
>>   implementation-dependent method.   Note that you should declare a routine as
>>   EXTERNAL in order to pass it as an argument.
>>
>>I'm unaware of any need for the length of a CHARACTER FUNCTION argument
>>to be passed to a called procedure in the ANSI FORTRAN 77 standard.
>>As far as I know, the actual caller of the function (via a dummy) must
>>know (or declare) the length of the returned value.
>
>     Consider the following bit of code which, I believe, is perfectly
>standard conforming:
>
>       PROGRAM DUMB
>       character*10 func,arg
>       arg = func()
>       write(*,*)arg
>       END
>
>       FUNCTION FUNC()
>       character*(*) func
>       func = 'abcdefghijklmnopqrstuvwxyz'
>       END
>
>The function must know len(func) since it must not overwrite memory past
>the end of that assigned to the return value.  In other words, some
>mechanism must exist for FUNC to know its declared length.  One way to
>do this is for len(func) to be passed as a supplementary, invisible (to
>the programmer) parameter to the function call.

This is right, but it doesn't address the original question which
was about passing character functions as arguments.  As I understand
f77, the code

      program dumb
      character*10 cfun, cvar
      external cfun
      call sub( cvar, cfun )
      write(*,*) 'cvar=', cvar
      stop
      end
      subroutine sub( cvar, cfun )
      character*(*) cvar, cfun
c     # the following statement is not legal with *(*) declaration
c     # but is legal with *10 declaration.
      cvar = cfun()
      return
      end
      function cfun
      character*(*) cfun
      cfun = '12345678901234567890'
      return
      end

is not legal for the reason given above in the comments.  In fact, if
the argument list to sub() is extended to include the length variable,
it is STILL not legal.

      ...
      call sub( cvar, cfun, 10 )
      ...
      subroutine sub( cvar, cfun, len )
      character*(len) cvar, cfun
      ...

The only way to make it legal is to use a constant, or a parameter,
in the type declaration within sub().  Note that it is the function
"cfun()" that causes the problems, not the variable "cvar".  All of
the above (e.g. *(*), *10, *(len)) works fine with "cvar".

The second paragraph of the standard on page 15-2 states: "If a
character function is referenced in a program unit, the function
length specified in the program unit must be an integer constant
expression."  This explains why "*10" is the only legal declaration
for "cfun()", whereas all three types of declarations are fine with
"cvar".  

Note that it is the REFERENCING of cfun() that is illegal, not the
declaration itself.  This means that external cfun() could be declared
as *(*) within sub(), and used as an argument in another call statement.
As long as it is declared as *(CONSTANT) in the subprogram in which it
is finally referenced, everything is alright.

The next question, of course, is why was this additional restriction
imposed on functions?  Maybe Burley can give some insight here, but my
guess is that the space associated with cfun() is allocated within
sub() instead of in the main program (where the space for cvar() is
associated.  Otherwise, expressions involving cfun() might require
runtime memory allocation, something which is carefully avoided in
character manipulations in f77.

-ron shepard
shepard@tcg.anl.gov
Newsgroups: comp.lang.fortran