> ... I want everybody to be assured that the CHARACTER
> data type is not on anybody's list of stuff to delete.
> Only two small things: the syntactic declarations
> of the form CHARACTER*length (there are a hundred
> other ways to do it, including CHARACTER(len=22)).
> The other is *length function results (I can never
> quite figure out how to use them anyway).
>
"Assumed character length function results" have been put on the
conveyor belt that may lead to eventual deletion a few cycles down
the road. It was introduced in F77 (along with most CHARACTER stuff).
Like Walt, I never used it and never particularly liked it, but I
saw it in some F77 programs that I got from eleswhere.
When I saw the listing in the F95 draft (p. 303 in the current
version), I thought something more useful was being deprecated, and
I was a bit frightened until I read it more carefully.
**** NOTE!!! ****
YOU WILL STILL HAVE AUTOMATIC LENGTH CHARACTER RESULTS. You will still
be able to declare the length of a result variable in a specification
expression that can depend, among other things, on the length of
an assumed-length string that is an input argument to the same
procedure. Maybe the F95 draft should add a couple of words in B.2.5 to
point out that automatic length is NOT what is being deprecated.
What you can't do (if the feature is ever finally eliminated) is to
declare the function name IN THE CALLING PROGRAM with a particular
character length, and then get the function result variable to
pick up that length FROM A "len=*" DECLARATION in the function.
Another way of putting it is that you can't leave the result length
"unspecified" in the function.
It's still true in F95 that assumed-length strings are analogous to
assumed-shape arrays (in all respects that make sense for strings --
for example, there is no concept of rank for strings) and
automatic-length is analogous to automatic-shape.
-Loren Meissner
But I want everybody to be assured that the CHARACTER
data type is not on anybody's list of stuff to delete.
Woops, sorry if I left THAT impression!!
Only two small things: the syntactic declarations
of the form CHARACTER*length (there are a hundred
other ways to do it, including CHARACTER(len=22)).
The other is *length function results (I can never
quite figure out how to use them anyway).
I think Loren clarified this...I had thought only CHARACTER*(*)-returning
functions would be deprecated over time, but now I'm a bit confused
so I won't so anything more on that topic until I get around to actually
learning about it!!
It's a matter of taste, of course, but to a good 'ol
top-down programmer, putting procedures after the main
program that calls them is the natural way to do it.
Oh, for sure, but the Fortran style is the opposite -- statement
functions, declarations, and so on all must _precede_ their
references. (Well, _almost_ all....)
Personally, it's always been a bit jarring for me to see source
files start off with bottom-dwellers, which is usually the case
for Pascal and C sources I've seen. But as (now) a long-time
C programmer using a compiler (gcc) that knows how to in-line
such things when seen in the canonical sequence (for C), I've
gotten used to not only reading lots of code written that way,
but writing it as well. I'm not thrilled about it, having
learned PL/I in the distant past and such, but that's the toolset
I'm using for the jobs I'm doing today.
My issue is that Fortran programmers aren't used to this. If
they see "S = RADIUS(R)", they expect RADIUS to be defined "above",
not "below", especially if it's an internal procedure. Further, if
it _is_ internal (which used to mean "statement function" only),
they'd expect the compiler to complain immediately upon seeing
an erroneous statement like "S = RADIUS(R,T)" rather than waiting
until it had finished processing the entire host program unit
and whatever internal procedures preceded the definition of RADIUS.
Further, the ability to make a one-pass compiler (definitely
useful to some audiences) is shot to pieces in F90, because one cannot
compile "R = SIN(S)" until one has looked all the way to the bottom
of the program unit to see whether it's a CONTAINSed procedure or
simply a reference to intrinsic SIN.
Sensitivity to these issues would have at least resulted in requiring,
or perhaps just allowing, declarations _preceding_ any code in the
host that say "the following names are internal procedures following
the CONTAINS below: RADIUS, SIN", at the very least (and perhaps
specifying the interfaces involved). (I would have loved at least
the requirement to say "CONTAINED::RADIUS,SIN" before any executable
code, for example.)
That would have mitigated both problems at least somewhat: it might
have allowed one-pass compilers to be built without having to have
mammoth "exception" code for cases where one-pass wasn't possible;
and it would ensure the programmer could always "look up" to find
at least some mention of the procedure being invoked (or know it must
be external/intrinsic), even if that mention just means "now look
down to find the actual internal procedure!".
Now I realize there are what _others_ might called "pointy-headed
academics" who pooh-pooh these concerns (then and now), but my
essential point stands: F90 doesn't seem to have allowed any
serious length of time during which these fundamental concerns
(that I've heard _real_ programmers express, in a variety of ways,
countless times) could have been experimentally evaluated vis-a-vis
placement of CONTAINS.
Personally, I still prefer _seeing_ the top-level code _followed_ by
the procedures it has invoked. (Though I take great issue with the
statement that this organization "encourages top-down design" -- yeah,
like anybody still types in code in one fell swoop without the benefit
of an editor that lets them enter code at the top of a file!! ;-)
But I wouldn't want to impose my personal preferences on an entire
community by virtue of creating standards...at least not without
testing them thoroughly first, and maybe even making sure most of
that community was already at the point of saying "yeah, that's the
right way to do things".
BTW, I don't understand why USE and INTERFACE, etc., must precede
references to procedures in the module as well. Why force that kind of
bottom-up writing of code? Couldn't F90 have let the programmer
write the code and then _follow_ it with whatever declarations,
definitions, or inclusion of packages that supports its need for
bottom-dwellers?? (For that matter, why is DATA being forced to the
_top_ of executable code in future revisions of Fortran, when even F77
allowed it to just precede END?? -- something I've never been particularly
thrilled with, by the way, though at least in practice, it doesn't
seem to preclude most useful and fast ways of dealing with DATA....)
(Partial ;-), since other languages like PL/I already allowed this
kind of flexibility, at least moreso than F90 or F95. So it
ain't unproven technology....)
Yes, there were some implementations of internal
procedures; perhaps some impelemntors will share with
us how they were done.
And, no, there (no/very few) "real" implementations
(i.e., from companies with three-letter names) with
IF-THEN-ELSE before 1977. Maybe somebody knows of
one other than a preprocessor?
That'd be great.
Meanwhile, again, IF/THEN/ELSE/ENDIF in its day was far less of a fundamental
change in the visual appearance of Fortran than CONTAINS (for programs
that were to be upgraded to use them).
After all, there were already DO blocks, in essence, so the idea of another
kind of block wasn't too radical. And one could, barring outside GOTOs,
exactly replace:
IF (A.NE.0) GOTO 10
stmts
10 more-stmts
with:
IF (.NOT.(A.NE.0)) THEN
stmt
ENDIF
more-stmts
But one cannot, unfortunately, replace:
RADIUS(R) = 2.*3.14159*R
with:
CONTAINS
REAL FUNCTION RADIUS(R)
RADIUS = 2.*3.14159*R
END FUNCTION RADIUS
END CONTAINS
And that is why I think the placement of CONTAINS was unfortunate --
it did not allow people to choose to upgrade to it without making
radical changes in the overall appearance of their code (among
other things, like the speed with which a typical compiler would be
able to spot invocation and other errors involving functions like
RADIUS), since they had to not only replace the statement function,
they had to _move_ it to the _opposite end_ of their code, without
being able to leave any _syntactically significant_ text where it
used to be (i.e. other than a comment, useless to a typical compiler
and often overlooked by experienced programmers who know comments
aren't maintained and checked by automated tools).
For a real-world example, ask yourself this. You've got a F90
compiler that, while not slow, cannot compile your 10,000-line
somewhat-monolithic code in less than about 10 minutes on your
system (maybe other users are using it). Your
code has a pretty big host section followed by, say, 2,000 lines
of CONTAINS (internal-procedure) stuff.
Now, you want to add a small-but-tricky internal procedure to it.
You know the tricks will be in getting the variable types right and
such, mainly stuff that the compiler will catch if you do it wrong.
(Maybe you're making heavy use of defined operators, pointers, module
association, whatever.)
So, you figure you might take as many as 5 iterations of compiling
to get this 10-line procedure working in context.
Now, how do you save yourself time without spending a lot of keystrokes
or risking accidentally losing most of your code if you get unlucky?
Me, I just temporarily place the new code at the very top of the file (or,
for a nested C procedure, at the top of its function where it belongs
anyway), and compile/edit repeatedly until no more compile errors
results. Then I move it to where it "belongs", perhaps well down into
the source file.
In F9x, you can't do this. The best you can hope for is to put it just
after the CONTAINS -- which appears, in this case, 8000 lines down into the
source code!!
Here, you're at least grateful a one-pass compiler is impossible,
because that means your compiler is not wasting time generating code
for the first 8,000 lines before it finally looks at your new code.
This is the _present_ state of most peoples' compiler toolsets today,
and it represents frequent, real-world cases like the ones I often
run into.
(Well, maybe it works to put it just after a dummy,
temporary CONTAINS just before the first executable statement in the
host code, if the compiler properly recognizes the sudden appearance
of code without a SUBROUTINE/FUNCTION statement...though it doesn't
cover cases where internal procedures invoke each other, unless you
move the _entire_ CONTAINS chunk to the top. As long as the compiler
quickly diagnoses what was the first executable statement as being
invalid in its context, you could be fine -- but since F90 requires
two-pass compilers, maybe most or all of them won't give you
enough useful diagnostics until the entire first pass on the 10K lines
of code is completed anyway!)
The good news for people like me who have grand ideas about designing
new compiler toolsets: F90, more than F77, offers a fertile user
community in terms of being receptive to the kind of speedups users
should see in the toolsets we have in mind!!
--
James Craig Burley, Software Craftsperson bur...@gnu.ai.mit.edu
> "Assumed character length function results" have been put on the
> conveyor belt that may lead to eventual deletion a few cycles down
> the road.
> ...
> YOU WILL STILL HAVE AUTOMATIC LENGTH CHARACTER RESULTS.
You will still have assumed character length dummy args also, of course.
>
> It's still true in F95 that assumed-length strings are analogous to
> assumed-shape arrays (in all respects that make sense for strings --
> for example, there is no concept of rank for strings) and
> automatic-length is analogous to automatic-shape.
>
Another obvious difference is that a string can't be "allocatable"
(although an array containing one string can be allocated -- you can
defer the array shape but not the string length).
Summary (see Chap 8 of my F90 text):
Arrays
======
* Local [this is the only kind in a main program]
Fixed shape
Automatic shape [not in main program]: dimensions given by a specifi-
cation expression
Deferred shape: allocatable or pointer target
----
My recommendation: Use fixed shape only if the shape is a "law of
nature" and cannot change. Use allocatable shape most of the time.
Allocatable is probably better than automatic.
* Dummy Arguments [not in main program]
Fixed shape
Assumed size (last dimension declared as "*")
Assumed shape
----
My recommendation: Never use assumed size [It was OK in F77 where
there was less flexibility, but not needed any more]. Use fixed
shape only if the shape is a "law of nature" and cannot change. Use
assumed shape most of the time.
Note: Fixed shape arrays will probably be passed as a "base address".
assumed shape as a descriptor address. Larry Rolison says the former
is A LOT more efficient, but High Performance Fortran says descriptors
enhance parallelizability.
* Function results [only in a function]
Fixed shape
Automatic shape
----
My recommendation: Use automatic shape for a function result array
whose shape is determined at function entry. Otherwise, fixed
shape is probably easier to understand.
Strings
======
* Local [this is the only kind in a main program]
Fixed length
Automatic length [not in main program]
* Dummy Arguments [not in main program]
Fixed length
Assumed length -- always think of this one first.
* Function results [only in a function]
Fixed shape
Automatic length -- if the result length is determined at entry.
Assumed length [deprecated in F95 draft]
==================
Have I left anything out?
-- Loren Meissner
But I want everybody to be assured that the CHARACTER
data type is not on anybody's list of stuff to delete.
Only two small things: the syntactic declarations
of the form CHARACTER*length (there are a hundred
other ways to do it, including CHARACTER(len=22)).
The other is *length function results (I can never
quite figure out how to use them anyway).
It's a matter of taste, of course, but to a good 'ol
top-down programmer, putting procedures after the main
program that calls them is the natural way to do it.
Yes, there were some implementations of internal
procedures; perhaps some impelemntors will share with
us how they were done.
And, no, there (no/very few) "real" implementations
(i.e., from companies with three-letter names) with
IF-THEN-ELSE before 1977. Maybe somebody knows of
one other than a preprocessor?
--
Walt Brainerd wa...@fortran.com
Unicomp, Inc. +1-505-275-0800 856-1501 (fax)
1874 San Bernardino Ave NE +1-500-Fortran (367-8726)
Albuquerque, NM 87122 USA http://www.fortran.com/fortran/