Home > Archive > Fortran > January 2006 > Does the order of declarations matter?
You are viewing an archived Text-only version of the thread.
To view this thread in it's original format and/or if you want to reply to
this thread please [click here]
| Author |
Does the order of declarations matter?
|
|
| ejko123@yahoo.com 2006-01-25, 7:10 pm |
| More precisely, is the following code fragment standard-conforming:
subroutine sub(dum,n)
real,intent(inout):: dum(n)
integer,intent(in):: n
! rest of sub
end subroutine
Or must the declaration for N appear before the declaration
of DUM?
Related question: Is there a difference between
subroutine sub2(iarray,n)
integer,intent(in):: iarray(n),n
and
integer,intent(in):: n,iarray(n)
I've been looking at my copy of Adams & Brainerd and don't see
this issue addressed specifically. Comments appreciated.
--Eric
| |
| James Van Buskirk 2006-01-25, 7:10 pm |
| <ejko123@yahoo.com> wrote in message
news:1138214075.359667.137670@g43g2000cwa.googlegroups.com...
> More precisely, is the following code fragment standard-conforming:
> subroutine sub(dum,n)
> real,intent(inout):: dum(n)
> integer,intent(in):: n
> ! rest of sub
> end subroutine
> Or must the declaration for N appear before the declaration
> of DUM?
Obviously a trick question! Looking at ISO/IEC 1539-1:1997(E),
section 7.1.6.2:
"A variable in a specification expression shall have its type
and type parameters, if any, specified by a previous declaration
in the same scoping unit, or by the implicit typing rules in
effect for the scoping unit, or by host or use association. If
a variable in a specification expression is typed by the
implicit typing rules, its appearance in any subsequent type
declaration statement shall confirm the implied type and type
parameters."
Thus the place to look to decide standard conformance is the
host procedure or module that sets the default typing rules for
subroutine sub. If implicit none is in force there, or n
has implicit type that is not integer or kind type paraemter
that is not that of a default integer, the code is not
standard conforming. If there is no host, or the host implicitly
types n as a default integer, the code is OK.
> Related question: Is there a difference between
> subroutine sub2(iarray,n)
> integer,intent(in):: iarray(n),n
> and
> integer,intent(in):: n,iarray(n)
Section 7.1.6.2 goes on to say:
"If a specification expression includes a reference to an
inquiry function for a type parameter or an array bound of
an entity specified in the same specification-part, the type
parameter or array bound shall be specified in a prior
specification of the specification-part. The prior
specification may be to the left of the inquiry function in
the same statement. If a specification expression includes a
reference to the value of an element of an array specified in
the same specification-part, the array shall be completely
specified in prior declarations."
I think this means that the first declaration above is only
OK if n is implicitly default integer, but the second is
always OK because n is not an array. Umm... the last
paragraph above is changed by Corrigendum 2:
"If a specification expression includes a reference to an
inquiry function that depends on a type parameter or an array
bound of an entity specified in the same specification-part,
the type parameter or array bound shall be specified in a prior
specification of the specification-part. The prior
specification may be to the left of the inquiry function in
the same statement, but shall not be within the same entity-
decl. If a specification expression includes a reference to
the value of an element of an array specified in the same
specification-part, the array shall be completely specified in
prior declarations."
Doesn't seem to change my interpretation, though.
--
write(*,*) transfer((/17.392111325966148d0,6.5794487871554595D-85, &
6.0134700243160014d-154/),(/'x'/)); end
| |
| Richard E Maine 2006-01-25, 7:10 pm |
| In most cases, order of declarations does not matter, but there are a
few cases where it does. (I have heard from people who should know that
the existing restrictions are a bit conservative for today's compiler
technology, and could be relaxed quite a bit, bit that's a question for
the future).
<ejko123@yahoo.com> wrote:
> More precisely, is the following code fragment standard-conforming:
>
> subroutine sub(dum,n)
> real,intent(inout):: dum(n)
> integer,intent(in):: n
>
> ! rest of sub
> end subroutine
>
> Or must the declaration for N appear before the declaration
> of DUM?
Well, this one is standard-conforming, but only for a slightly obscure
reason. Add an implicit none and this would no longer be standard
conforming. The relevant section of f2003 is 7.1.6, where "specification
expression" is defined. The "n" used as a dimension here is a simple
case of a specification expression. From the first para after Note 7.9
on pg 126
"A variable within a specification expression shall have its type
and type parameters, if any, specified by a previous declaration
in the same scoping unit, by the implicit typing rules in effect
for the scoping unit, or by host or use association. If a variable
in a specification expression is typed by the implicit typing rules,
its appearance in any subsequent type declaration statement shall
confirm the implied type and type parameters."
and thenthere is another para about order requirements when something
depends on a type parameter or array bound, but that doesn't apply to
this case.
Anyway, the only reason that the sample above is ok is that the implicit
type for n is "right". Even though n ends up getting explicitly typed,
the implicit typing matters. Yes, I find this slightly strange. So if
the variable name was, say, en instead of n, it would be illegal. Or if
you used implicit none. I might summarize it as that this ordering is
basically "wrong", but this particular case is "rescued" by what I'd
consider a technicality.
> Related question: Is there a difference between
>
> subroutine sub2(iarray,n)
> integer,intent(in):: iarray(n),n
> and
> integer,intent(in):: n,iarray(n)
Oh, darn. That one is harder. There was an interp on that kind of
question, but I don't recall the answer. Again, in this exact case, it
is valid anyway because the implicit typing is "right". But if the
implicit typing were wrong, then I'm sure that, say
integer :: iarray(en), en
would be illegal because en certainly wouldn't be declared in a
"previous declaration" in any sense. What I'm less sure of is whether
integer :: en, iarray(en)
would actually be good enough; that is does the declaration of en then
count as a previous one or part of the same one?
Let's see...... Ah. There is what I was thinking of - F95 interp 95,
which I see is more about the next para than this one. There is much
opportunity for complication here with circular dependence of type
parameters and array sizes. But even though it isn't this exact
question, I do see as part of the answer that
"A prior specification refers to a specification in a previous
<entity-decl> or in a previous statement."
The en and iarray(en) are <entity-decl>s here, so I think that having
the order as "en,iarray(en)" is good enough; the en doesn't have to be
in a previous statement.
--
Richard Maine | Good judgment comes from experience;
email: my first.last at org.domain| experience comes from bad judgment.
org: nasa, domain: gov | -- Mark Twain
| |
|
| ejko123@yahoo.com wrote in message <1138214075.359667.137670@g43g2000cwa.googlegroups.com>...
>More precisely, is the following code fragment standard-conforming:
>
> subroutine sub(dum,n)
> real,intent(inout):: dum(n)
> integer,intent(in):: n
>
> ! rest of sub
> end subroutine
>
>Or must the declaration for N appear before the declaration
>of DUM?
Why do you want to do this?
The passing of N is redundant, as the bounds of the argument
are passed to dum. Try --
subroutine sub(dum)
real,intent(inout):: dum( : )
integer :: n
! rest of sub
end subroutine
n can be assigned to ubound(dum).
| |
| Jan Vorbrüggen 2006-01-26, 3:59 am |
| > Why do you want to do this?
> The passing of N is redundant, as the bounds of the argument
> are passed to dum.
No, these are two different types of arguments - IIRC, one is assumed-size
and the other is assumed-shape. And it matters: the former does not, and
the latter definitely does, need an explicit interface.
Jan
| |
| glen herrmannsfeldt 2006-01-26, 7:02 pm |
| robin wrote:
> ejko123@yahoo.com wrote in message <1138214075.359667.137670@g43g2000cwa.googlegroups.com>...
[color=darkred]
[color=darkred]
[color=darkred]
I don't see any restriction on it in Fortran 66, though it wasn't
an initialization expression in that case.
F2003 has in C714:
The prior specification may be to the left of the specification
inquiry in the same statement, but shall not be within the same
entity-decl.
[color=darkred]
> Why do you want to do this?
> The passing of N is redundant, as the bounds of the argument
> are passed to dum. Try --
> subroutine sub(dum)
> real,intent(inout):: dum( : )
> integer :: n
The N is not redundant for assumed size arrays. Many subroutine
libraries still have programs written in older Fortran versions.
(Now, why do they call it assumed size when you have to tell it
what the size is?)
-- glen
| |
| Richard E Maine 2006-01-26, 7:03 pm |
| glen herrmannsfeldt <gah@ugcs.caltech.edu> wrote:
> I don't see any restriction on it in Fortran 66, though it wasn't
> an initialization expression in that case.
It isn't in this case either. It is a specification expression.
> F2003 has in C714:
I'm completely by the mention of C714. This simply is not even
close to related to C714, which is a constraint on initialization
expressions o logical type. Maybe a typo or something here, but I can't
even reverse enginneer the typo. C714 is physically close in the text,
being on the facing page; maybe that's related. Anyway...
> The prior specification may be to the left of the specification
> inquiry in the same statement, but shall not be within the same
> entity-decl.
This is not relevant because it is in a para about specification
inquiries. There are no specification inquiries involved. It is the
previous para that is relevant, as mentioned in my earlier post.
> (Now, why do they call it assumed size when you have to tell it
> what the size is?)
The size in an assumed-size array is "assumed from" the actual argument,
just like the shape in an assumed-shape array is "assumed from" the
actual argument.
But maybe the reason you are is different. You do not tell it
the size of an assumed-size array. If you tell it the size (indirectly,
by telling it all the bounds), then the array is no longer assumed-size,
but is explicit shape.
--
Richard Maine | Good judgment comes from experience;
email: my first.last at org.domain| experience comes from bad judgment.
org: nasa, domain: gov | -- Mark Twain
| |
| Richard E Maine 2006-01-26, 7:03 pm |
| Jan Vorbrüggen <jvorbrueggen-not@mediasec.de> wrote:
>
> No, these are two different types of arguments - IIRC, one is assumed-size
> and the other is assumed-shape. And it matters: the former does not, and
> the latter definitely does, need an explicit interface.
That's not the only reason it matters. There can be huge performance
differences in some cases because of copy-in/copy-out issues discussed
before. I have personally observed performance differences of 2 or 3
orders of magnitude, and have heard tales of worse. (Ok, those ar
extreme cases, but they do come up in real applications - anyway mine
did.)
--
Richard Maine | Good judgment comes from experience;
email: my first.last at org.domain| experience comes from bad judgment.
org: nasa, domain: gov | -- Mark Twain
| |
| Michael Prager 2006-01-26, 7:03 pm |
| nospam@see.signature (Richard E Maine) wrote:
>
>That's not the only reason it matters. There can be huge performance
>differences in some cases
So which is faster? I would guess assumed-size (as a simpler
and older construct), but please clarify.
Thanks!
--
Mike Prager, NOAA, Beaufort, NC
Address spam-trapped; remove color to reply.
* Opinions expressed are personal and not represented otherwise.
* Any use of tradenames does not constitute a NOAA endorsement.
| |
| Richard E Maine 2006-01-26, 7:03 pm |
| Michael Prager <Mike.Prager.indigo@noaa.gov> wrote:
> nospam@see.signature (Richard E Maine) wrote:
>
>
> So which is faster? I would guess assumed-size (as a simpler
> and older construct), but please clarify.
It has been much-discussed here before. Short answer - it depends. :-)
The multiple orders of magnitude that I ran into were cases where
assumed-size was far slower. I ran into it in the early days of f90,
while trying to figure out why a program of mine worked correctly, but
performed so poorly. I was using the NAG compiler (the only f90 one in
existance at the time), and I studied the intermediate C code for hints.
I noticed, to my surprise, that copy-in/copy-out was happening, which
was what was killing the performance. I had cases where an entire array
was being copied in and out of a one-line subroutine, which did nothing
but set the value of one element of the array. On looking back at my
Fortran code, I understood why... and then marvelled that the compiler
was "smart" enough to make the kind of thing I was doing work at all.
But "smart" as the compiler was, I didn't think that nearly smart
enough. I went back and changed the way I was doing things so that
copy-in/copy-out wouldn't happen. Sped up the routine in question by
about 2 or 3 orders of magnitude, and the whole application by about a
factor of 2 (the routine in question was "normally" a negligable part of
the processing time).
There are other cases where assumed shape can be slower, mostly due to
having a stride that is not known at compile time. The penalties for
that are much smaller - none of this orders of magnitude bit - but folks
trying for the top performance sometimes care; it has never hit me in a
big enough way for me to care. The NAG compiler (and I think some
others) has a switch to allow you to essentially force the
copy-in/copy-out for those cases where the benefit of the
compile-time-known stride outweighs the costs of the copy-in/copy-out
(which would be in a very different kind of routine from the small
one-liner that I had the problems with).
--
Richard Maine | Good judgment comes from experience;
email: my first.last at org.domain| experience comes from bad judgment.
org: nasa, domain: gov | -- Mark Twain
| |
|
| Jan Vorbrüggen wrote in message <43rgvpF1o5464U2@individual.net>...
[color=darkred]
>No, these are two different types of arguments - IIRC, one is assumed-size
>and the other is assumed-shape. And it matters: the former does not, and
>the latter definitely does, need an explicit interface.
I asked, because the OP used the old way, and is prone to error.
Better to pick up n from the actual bound of dum, rather than
passing it as a separate argument.
BTW, an explicit interface is always safer.
> Jan
| |
| glen herrmannsfeldt 2006-01-26, 9:56 pm |
| Richard E Maine wrote:
> Jan Vorbrüggen <jvorbrueggen-not@mediasec.de> wrote:
(snip)
[color=darkred]
> That's not the only reason it matters. There can be huge performance
> differences in some cases because of copy-in/copy-out issues discussed
> before. I have personally observed performance differences of 2 or 3
> orders of magnitude, and have heard tales of worse. (Ok, those ar
> extreme cases, but they do come up in real applications - anyway mine
> did.)
If you use one element after copying in N elements, and then copying
them back it could be 2N times slower.
A non-contiguous array that is big enough to thrash the cache could
easily be 1 order of magnitude slower than a contiguous copy.
-- glen
| |
| ejko123@yahoo.com 2006-01-27, 3:59 am |
|
robin wrote:
> I asked, because the OP used the old way, and is prone to error.
> Better to pick up n from the actual bound of dum, rather than
> passing it as a separate argument.
The old way is better unless there are compelling reasons
to do otherwise. The main reason is for clarity; another is
performance.
For example, the declarations
integer, intent(in):: k,m,n
real,intent(in):: a(k,m), b(m,n)
real,intent(out):: c(k,n)
make clear the programmer's expectations regarding the sizes
of the arrays; it's also obvious from the declarations that
c=matmul(a,b)
is well-defined. It's much harder to infer the programmer's intent
from declarations of the form
real,intent(in):: a(:,:), b(:,:)
and so on; one must search through the rest of the code to
find out, and the constructs are clumsy:
if(size(a,1) == size(c,1) .and. size(a,2)==size(b,1) .and. &
size(b,2) == size(c,2)) then
c=matmul(a,b)
etc.
Most compilers generate faster code from the first set of
declarations than the second (assuming that the actual
arrays are contiguous in memory) because the compiler
does not need to deal with a dope vector to do the requisite
addressing. SGI (among others) states that four times as
many instructions must be generated to index a (:,:) array than
an (m,n) array.
Explicit shape (the first set above) has the di vantage that
the programmer must manage extra dummy arguments, which
can be problematic. Assumed shape (second set) sometimes
is preferable if one wants to write a generic subroutine to perform
some action on an array without the overhead of passing dimensions.
Either way, however, the programmer must get the correspondence
between actual and dummy arrays correct for the code to work,
and explicit-shape declarations are quite helpful for this purpose.
There was a discussion awhile back about the possibility of a future
INFERRED attribute, which would provide a run-time check
on the consistency of explicit-shape arguments. I think it would
be a nice facility that would improve the robustness of many programs.
--Eric
| |
| Jan Vorbrüggen 2006-01-27, 3:59 am |
| > SGI (among others) states that four times as many instructions must be
> generated to index a (:,:) array than an (m,n) array.
Then they should hire, for instance, one of the DEC Fortran compiler guys
- they knew, even twenty years ago, how to get things of this kind right.
There is no reason for the statement attributed to SGI above to be true.
Run-time decision of which code variant to use is one way to solve this.
Jan
| |
| Jan Vorbrüggen 2006-01-27, 7:58 am |
| > There are other cases where assumed shape can be slower, mostly due to
> having a stride that is not known at compile time.
The other case, of course, is that the intrinsic performance of operations
on the discontiguous or the contiguous copy of the data may be widely
different, e.g., due to cache effects. In this case, the programmer obvious-
ly always has the option of doing the copy-in/copy-out explicitly. That,
in my opinion, is better (if somewhat more onerous) than asking the compiler
to do some behind-the-scenes magic that isn't portable and is obscure (from
a maintainability point-of-view).
Jan
| |
|
| glen herrmannsfeldt wrote in message <5didnbSU0tu XeRVn-jQ@comcast.com>...
>robin wrote:
>
>
>
>
>
>
>The N is not redundant for assumed size arrays.
That is the old way, as I explained in an earlier post.
The modern, safer, way is preferred.
> Many subroutine
>libraries still have programs written in older Fortran versions.
We are not talking about old versions. He is using
F90 or later, for which the bounds are passed along with
the array elements, as shown.
| |
| Michael Prager 2006-01-27, 7:01 pm |
| Glad to see consensus on this, as on so many issues.
Maybe I should ask which editor is the best?
NO, forget I said that!
M
--
Mike Prager, NOAA, Beaufort, NC
Address spam-trapped; remove color to reply.
* Opinions expressed are personal and not represented otherwise.
* Any use of tradenames does not constitute a NOAA endorsement.
| |
| Richard E Maine 2006-01-27, 7:01 pm |
| Michael Prager <Mike.Prager.indigo@noaa.gov> wrote:
> Maybe I should ask which editor is the best?
I'll freely admit that Malcolm is, and I was glad to hand over
editorship to him after I had done my penance for a decade.
Or did you mean something different? :-)
--
Richard Maine | Good judgment comes from experience;
email: my first.last at org.domain| experience comes from bad judgment.
org: nasa, domain: gov | -- Mark Twain
| |
|
| ejko123@yahoo.com wrote in message <1138334650.498277.110620@g49g2000cwa.googlegroups.com>...
>
>robin wrote:
>
>
>The old way is better unless there are compelling reasons
>to do otherwise. The main reason is for clarity; another is
>performance.
>
>For example, the declarations
> integer, intent(in):: k,m,n
> real,intent(in):: a(k,m), b(m,n)
> real,intent(out):: c(k,n)
>
>make clear the programmer's expectations regarding the sizes
>of the arrays; it's also obvious from the declarations that
> c=matmul(a,b)
matmul? nobody said anything about matmul in this problem.
As I said before, this form is error prone, and
in any case, the programmer still has to perform any checks
that might be needed on the bounds of the arrays.
>is well-defined. It's much harder to infer the programmer's intent
>from declarations of the form
> real,intent(in):: a(:,:), b(:,:)
>and so on; one must search through the rest of the code to
>find out,
find out what?
Hopefully, the purpose of the subroutine will be spelled out
in a description.
> and the constructs are clumsy:
> if(size(a,1) == size(c,1) .and. size(a,2)==size(b,1) .and. &
> size(b,2) == size(c,2)) then
> c=matmul(a,b)
>etc.
>
>Most compilers generate faster code from the first set of
>declarations than the second (assuming that the actual
>arrays are contiguous in memory) because the compiler
>does not need to deal with a dope vector to do the requisite
>addressing. SGI (among others) states that four times as
>many instructions must be generated to index a (:,:) array than
>an (m,n) array.
>
>Explicit shape (the first set above) has the di vantage that
>the programmer must manage extra dummy arguments, which
>can be problematic. Assumed shape (second set) sometimes
>is preferable if one wants to write a generic subroutine to perform
>some action on an array without the overhead of passing dimensions.
>Either way, however, the programmer must get the correspondence
>between actual and dummy arrays correct for the code to work,
>and explicit-shape declarations are quite helpful for this purpose.
>
>There was a discussion awhile back about the possibility of a future
>INFERRED attribute, which would provide a run-time check
>on the consistency of explicit-shape arguments. I think it would
>be a nice facility that would improve the robustness of many programs.
>
>--Eric
>
| |
| James Giles 2006-01-31, 7:02 pm |
| Jan Vorbrüggen wrote:
>
> No, these are two different types of arguments - IIRC, one is
> assumed-size and the other is assumed-shape. And it matters: the
> former does not, and the latter definitely does, need an explicit
> interface.
Nitpicking:
real :: dum(*) ! is assumed size.
real :: dum(:) ! is assumed shape
real :: dum(n) ! is explicit shape
Assumed size and explicit shape are similar in some
ways (both associate by sequence association, for
example). Neither requires an explicit interface.
--
J. Giles
"I conclude that there are two ways of constructing a software
design: One way is to make it so simple that there are obviously
no deficiencies and the other way is to make it so complicated
that there are no obvious deficiencies." -- C. A. R. Hoare
|
|
|
|
|