home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #30 / NN_1992_30.iso / spool / comp / lang / fortran / 4716 < prev    next >
Encoding:
Internet Message Format  |  1992-12-15  |  9.1 KB

  1. Path: sparky!uunet!stanford.edu!snorkelwacker.mit.edu!ai-lab!life.ai.mit.edu!burley
  2. From: burley@apple-gunkies.gnu.ai.mit.edu (Craig Burley)
  3. Newsgroups: comp.lang.fortran
  4. Subject: SUMMARY: CHARACTER FUNCTION as dummy argument
  5. Date: 15 Dec 92 04:48:25
  6. Organization: Free Software Foundation 545 Tech Square Cambridge, MA 02139
  7. Lines: 222
  8. Message-ID: <BURLEY.92Dec15044825@apple-gunkies.gnu.ai.mit.edu>
  9. NNTP-Posting-Host: apple-gunkies.gnu.ai.mit.edu
  10.  
  11. Okay, I'll take a shot at summarizing what we've learned from this
  12. thread.  I might get things wrong, so stay on your toes, you
  13. standards experts!  :-)  Also, I haven't kept track of who has contributed
  14. what to this discussion as I should have -- very little of it
  15. is original with me, and most of that is clearly stated as my
  16. opinion anyway.  (I did come up with the problem shown in Sample 6,
  17. however, whereby the length of a return value is never established,
  18. and pointed out the inefficiency of the VAX/VMS FORTRAN extension to
  19. support Sample 1, for what that's worth.)
  20.  
  21. First off, the specific situation being addressed is this:
  22.  
  23. C Sample 1:
  24.     SUBROUTINE X(CFUNC)
  25.     CHARACTER*(*) CFUNC
  26.     EXTERNAL CFUNC
  27. C (EXTERNAL is optional since there's a reference to CFUNC next.)
  28.     PRINT *, CFUNC()
  29.     END
  30.  
  31. To make sure we're on the same page, what is happening here is this:
  32. presumably some program unit in the program calls X, passing in the
  33. first argument a CHARACTER FUNCTION external procedure (or, I suppose,
  34. an intrinsic; CHAR is the only one available in ANSI FORTRAN 77, but
  35. it is not standard-conforming to pass it as an actual argument
  36. [see 15-3 38-45]).  X declares no length for the procedure via the *(*)
  37. construct, then references the procedure.
  38.  
  39. Because X both references the CFUNC procedure and declares it as *(*),
  40. X is _not_ a standard-conforming program unit in Sample 1 [15-2 5-7].
  41.  
  42. The following two Samples are, however, standard-conforming (and GNU
  43. Fortran, currently in alpha test, will accept them as soon as I change
  44. it to do so -- thanks folks for getting me to try this out! :-):
  45.  
  46. C Sample 2
  47.     CHARACTER*(*) CFUNC
  48.     EXTERNAL CFUNC
  49.     CALL Y(CFUNC)
  50.     END
  51.  
  52. C Sample 3
  53.     SUBROUTINE Y(CFUNC)
  54.     CHARACTER*(*) CFUNC
  55.     EXTERNAL CFUNC
  56.     CALL X(CFUNC)
  57.     END
  58.  
  59. The reason both of the above Samples are standard-conforming is that
  60. they do not contain _references_ to CFUNC, so even though CFUNC is
  61. clearly a procedure, [15-2 5-7] is not violated.  Only a program unit
  62. that actually _references_ a CHARACTER FUNCTION must declare it via
  63. CHARACTER*n, where n is an integer constant expression.
  64.  
  65. Now, it is _possible_ to extend the language to permit Sample 1, and
  66. VAX/VMS FORTRAN does so.  However, doing so affects (negatively) the
  67. performance of standard-conforming code, because the return length of
  68. any CHARACTER FUNCTION (not just *(*) ones) must be passed along with
  69. the function in case the ultimate caller (the program unit doing the
  70. reference) declares the procedure with *(*) instead of *n.  In
  71. my opinion, extensions that even slightly reduce the performance of
  72. programs that don't use them are not wise as a default.  (So if I add
  73. the extension to GNU Fortran, which seems hard-to-impossible while it
  74. uses f2c-compatible calling sequences by the way, I'll add it so it has
  75. to be turned on via a command-line option when compiling _all_ related
  76. source files.  Hardly seems worth it, and see below for more problems with
  77. this kind of extension.)
  78.  
  79. As to the why's and wherefores:
  80.  
  81. ANSI FORTRAN 77 is set up so dynamic allocation is _never_ required by
  82. a standard-conforming program, either via heap or stack allocation.
  83.  
  84. When a compiler sees code like this:
  85.  
  86. C Sample 4
  87.     CHARACTER*10 CFUNC
  88.     PRINT *, CFUNC()
  89.     END
  90.  
  91. The compiler knows it need only allocate, statically at compile time,
  92. 10 characters of memory to hold the value returned by CFUNC.  In fact,
  93. generally, in a static-allocation model, it is always the _caller_ of
  94. a function that allocates (statically) space for the return value.  The
  95. callee can't allocate it statically because it can't know how many
  96. outstanding return values must be maintained before they are no longer
  97. needed by the caller, as in:
  98.  
  99. C Sample 5
  100.     CHARACTER*10 CFUNC
  101.     CALL FOO (CFUNC(), CFUNC())
  102.     END
  103.  
  104. If CFUNC was responsible for allocating space for its own return value,
  105. and that allocation was done statically, then the second invocation of
  106. CFUNC would overwrite the first (no matter the order of invocation) and
  107. FOO would see two identical results even though CFUNC might return
  108. different values each time.
  109.  
  110. So, if the _caller_ has to allocate static space for the return value,
  111. which is indeed the case, it must know how much space to allocate.
  112.  
  113. Going back to Sample 1, which is repeated here,
  114.  
  115. C Sample 1:
  116.     SUBROUTINE X(CFUNC)
  117.     CHARACTER*(*) CFUNC
  118.     EXTERNAL CFUNC
  119. C (EXTERNAL is optional since there's a reference to CFUNC next.)
  120.     PRINT *, CFUNC()
  121.     END
  122.  
  123. the caller of CFUNC, X, does not know how much space to allocate for
  124. CFUNC's return value.
  125.  
  126. So, how does VAX/VMS FORTRAN support code like in Sample 1?  Apparently,
  127. it resorts to dynamic allocation in this case, but apparently it _also_
  128. relies on the caller of X having declared CFUNC as *n, not *(*) (which,
  129. as demonstrated in Samples 2 and 3, would be standard-conforming),
  130. and mandates that all CHARACTER FUNCTION arguments are passed along with
  131. info on their declared length.  The latter aspect is, as I said above,
  132. troubling because it has to be done even for programs that don't use this
  133. extension, and because it seems possible (unless documented as unsupported)
  134. to have a reference to a CHARACTER*(*) FUNCTION that contains _no_
  135. information on the length of the return value.  The former aspect is simply
  136. an extension used when necessary, but something that goes outside the
  137. bounds of typical ANSI FORTRAN 77 implementations.
  138.  
  139. Now, one might point out that dynamic allocation could be avoided in
  140. Sample 1 by insisting that the caller of X (the "ancestor caller" of
  141. CFUNC) not only pass the return length of CFUNC but also pass a statically
  142. allocated place to store the return value of CFUNC.  However, this would
  143. introduce two problems:
  144.  
  145.     1.    Replacing PRINT *, CFUNC() with CALL FOO (CFUNC(), CFUNC())
  146.     would result in the same problem illustrated in Sample 5, whereby
  147.     the place provided by the ancestor caller of CFUNC to be written
  148.     by the first invocation of CFUNC would be overwritten by the second
  149.     invocation before calling FOO, so FOO would see two arguments with
  150.     the same value instead of two different values.
  151.  
  152.     2.  If the ancestor caller of CFUNC declared CFUNC as CHARACTER*(*) and
  153.     EXTERNAL before passing it it to X, which as shown in Samples 2 and
  154.     3 would be standard-conforming, then the ancestor caller _couldn't_
  155.     statically allocate space for X, and then if X itself was declared
  156.     CHARACTER*(*), _no_ code in the entire program unit would declare the
  157.     actual length of the return value of CFUNC!  (This is the problem that
  158.     VAX/VMS FORTRAN might have right now, as noted above; I think the
  159.     only way to handle it might be to "crash" at run time when an attempt
  160.     is made to invoke a function declared CHARACTER*(*) for which the
  161.     length is not known by the ancestor caller.)
  162.  
  163. So, once again we return to the simple requirement of a static-allocation
  164. strategy: the _caller_ is responsible for allocating space for the return
  165. value of a function, and therefore must know how much space to allocate
  166. at compile time.  That way, CALL FOO (CFUNC(), CFUNC()) is handled
  167. simply by allocating space for _two_ return values, each of which is
  168. 10 characters long (given CHARACTER*10 CFUNC).
  169.  
  170. If anyone has a system that supports the code in Sample 1 (like VAX/VMS
  171. FORTRAN), it'd be interesting to see how well it handled the following:
  172.  
  173. C Sample 6
  174.     CHARACTER*(*) CFUNC
  175.     EXTERNAL CFUNC
  176.     CALL X (CFUNC)
  177.     PRINT *, 'Done!'
  178.     END
  179. C
  180.     SUBROUTINE X (CFUNC)
  181.     CHARACTER*(*) CFUNC
  182.     EXTERNAL CFUNC
  183.     PRINT *, 'Try this:'
  184.     PRINT *, CFUNC()
  185.     PRINT *, 'Now try this:'
  186.     CALL Y (CFUNC(), CFUNC())
  187.     END
  188. C
  189.     SUBROUTINE Y (ARG1, ARG2)
  190.     CHARACTER*(*) ARG1, ARG2
  191.     PRINT *, ARG1(1:10), LEN (ARG1)
  192.     PRINT *, ARG2(1:10), LEN (ARG2)
  193.     END
  194. C
  195.     CHARACTER*(*) FUNCTION CFUNC ()
  196.     INTEGER I,J
  197.     CHARACTER C
  198.     SAVE I,C
  199.     DATA I/50/, C/'A'/
  200.     DO 10 J = 1, I
  201.        CFUNC(J:J) = C
  202. 10    CONTINUE
  203.     I = 2 * I
  204.     C = CHAR (ICHAR (C) + 1)
  205.     END
  206.  
  207. It _should_ print something like this:
  208.  
  209.     Try this:
  210.     AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
  211.     Now try this:
  212.     BBBBBBBBBB      100
  213.     CCCCCCCCCC      200
  214.     Done!
  215.  
  216. Or, maybe the BB... and CC... lines would be reversed, depending on how
  217. the compiler orders the calls to CFUNC in the CALL Y statement.
  218.  
  219. However, I can't imagine any implementation getting that "right", whatever
  220. right means.  The interesting info is just _how_ various implementations
  221. fail.  I claim that the only generally useful implementation is one that
  222. fails when compiling X by complaining that CFUNC cannot be both a CHARACTER*(*)
  223. FUNCTION and referenced, and that an implementation that extends the
  224. language so it doesn't complain so is making standard-conforming programs
  225. unecessarily inefficient and perhaps introducing other problems like
  226. the one shown above.
  227.  
  228. Hmm, maybe this isn't much of a summary after all!  :-)
  229. --
  230.  
  231. James Craig Burley, Software Craftsperson    burley@gnu.ai.mit.edu
  232. Member of the League for Programming Freedom (LPF) lpf@uunet.uu.net
  233.