subroutine main
:
call internal
:
contains
subroutine internal
do i=...
if (...) return
enddo
end subroutine
end
Should the undeclared variable "i" be in the scope of "main", i.e.
should it have the right do loop value in "main" after the call?
Admittedly this is somewhat "sloppy" coding, but all the Fortran-95
compilers I use except Gfortran answer "yes" to the question.
Gfortran requires me to put an "integer i" declaration at the top of
main.
Al Greynolds
You didn't show all the code. It matters. A lot. In particular...
If there is literally nothing but the code shown, then i is in the scope
of the internal pricedure, not in the main program. It becomes udefined
on return to the main program.
But... how did you detect this? If you do *ANYTHING*, and I mean that
"anything" at all with an i in the main program, then that changes the
answer. Then the i is in the main program and the internal procedure
gets it by host association. That "anything" includes such things as
printing the value of i to check.
Heissenburg comes to mind.
--
Richard Maine | Good judgement comes from experience;
email: last name at domain . net | experience comes from bad judgement.
domain: summertriangle | -- Mark Twain
I think you'll need to show actual code because it works for
me (for some definition of 'works').
troutmask:kargl[233] cat k.f90
program a
call internal
print '(A,I0)', '6 --> ', i
contains
subroutine internal
do i = 1, 5
print '(A4,I0)', 'i = ', i
end do
end subroutine internal
end program a
troutmask:kargl[234] gfc -o z k.f90
troutmask:kargl[235] ./z
i = 1
i = 2
i = 3
i = 4
i = 5
6 --> 6
You're right, I did forget that "i" was assigned and used for other
purposes in "main" and therefore must be in its scope. I'll have to
do some more investigation with the full (1000 line subroutine) source
to see why inserting the "integer i" declaration makes the gfortran
results agree with everyone else.
Al
program main
call something
end
subroutine something
i=1; n=7
call internal(5)
write(*,*) i
contains
subroutine internal(j)
intent(in) j
do i=j,n
if (i==4) return
enddo
end subroutine
end
Nevermind, this has not been a lucid day for me. The above example is
crap! I'll get back to you guys when I have something REAL to report.
> OK, the problem is a bug in gfortran as illustrated by the following
> simple but complete code that should obviously print 4 (not 8)
> subroutine something
> i=1; n=7
> call internal(5)
> write(*,*) i
> contains
> subroutine internal(j)
> intent(in) j
> do i=j,n
> if (i==4) return
> enddo
> end subroutine
> end
8 looks right to me. I don't see how it could be 4.
-- glen
program main
call something
end
subroutine something
! integer i !correct results from gfortran depend on this statement
character lit*1,line*100
lit(i)=line(i:i)
i=1; n=5; line='PZ0R1'
if (internal(4)) stop
write(*,*) i
contains
logical function internal(j)
intent(in) j
do i=j,n
k=index('RE',lit(i)); if (k==0) cycle
if (i+1==n) exit
enddo
internal=k==0
end function
end
> Finally, here's the code that gfortran has problems with:
> program main
> call something
> end
> subroutine something
> ! integer i !correct results from gfortran depend on this statement
> character lit*1,line*100
> lit(i)=line(i:i)
> i=1; n=5; line='PZ0R1'
> if (internal(4)) stop
> write(*,*) i
> contains
> logical function internal(j)
> intent(in) j
> do i=j,n
At this point, j=4, i=4, n=5
> k=index('RE',lit(i)); if (k==0) cycle
now k=1, i=4, n=5, the following exit is done.
> if (i+1==n) exit
> enddo
Now k=1, i=4
> internal=k==0
internal=.FALSE.
> end function
> end
The function returns .FALSE., stop is not executed, and i
(still 4) is printed, with or without the integer i statement.
Looks fine to me.
-- glen
lnx:scratch : gfortran blah.f90
lnx:scratch : a.out
4
lnx:scratch :
what do you see when you run your example? What do you expect to see?
FWIW:
lnx:scratch : g95 blah.f90
lnx:scratch : a.out
4
lnx:scratch : lf95 blah.f90
Encountered 0 errors, 0 warnings in file blah.f90.
lnx:scratch : a.out
4
lnx:scratch : pgf90 blah.f90
lnx:scratch : a.out
4
cheers,
paulv
p.s. I assume the lit(i)=line(i:i) is an oversight since i isn't set yet?
--
Paul van Delst Ride lots.
CIMSS @ NOAA/NCEP/EMC Eddy Merckx
That's what I came up with too. But he doesn't say what
*he* expects. Nor does he say what gfortran does with
or without the explicit declaration. I can well believe that
gfortran might have problems. For such a small code
fragment it manages to use a awful lot of less common
features (CYCLE, statement functions, host association
of statement functions, and so on). Especially when
two or more uncommon features interact, compilers
are known to have bugs.
--
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
I'm using the June 28 MacOSX Intel binary of gfortran 4.3 and I'm
definitely seeing a difference depending on whether "integer i" is
present. I think I'll shelf this until a newer Window's binary becomes
available.
Al
"lit" is a statement function!
Al
I kind of like statement functions. But they're getting so rare
that people no longer even recognize them.
Can you submit a bug report? The code works fine with gfortran
4.2.0 20070214, and fails with 4.3.0 20070630. It looks like a
possible problem with the statement function.
D'oh. Yeah, I realized that after I posted.
cheers,
paulv
Yep - count me in that group. I wouldn't even have worried more about it all except for
the explicit output from the Lahey compiler stating that it "Encountered 0 errors, 0
warnings...". That got me thinking since when I compile using that compiler I look for the
"variable <x> used but not set" warning output.
Sigh.
cheers,
paulv
Will do.
I'm pretty hard on the latest Fortran compilers (just ask Andy Vaught
or Steve Lionel) because there are old features, e.g. statements
functions, ENTRY, etc., that I (James too) still like. I also tend
tend to mix them freely with newer Fortran features. Until today,
Gfortran could not even completely compile my 3 year old application
without ICEs. At least now its down to getting it to execute properly
like the several other compilers I use.
Al
> glen herrmannsfeldt wrote:
>>awgre...@earthlink.net wrote:
>>The function returns .FALSE., stop is not executed, and i
>>(still 4) is printed, with or without the integer i statement.
>>Looks fine to me.
> That's what I came up with too. But he doesn't say what
> *he* expects. Nor does he say what gfortran does with
> or without the explicit declaration.
As I didn't note it before, I have the x86-64 version 4.2.0
> I can well believe that
> gfortran might have problems. For such a small code
> fragment it manages to use a awful lot of less common
> features (CYCLE, statement functions, host association
> of statement functions, and so on). Especially when
> two or more uncommon features interact, compilers
> are known to have bugs.
I did wonder about host association of statement functions,
but if that didn't work it would fail pretty hard.
-- glen
> Paul van Delst wrote:
>>p.s. I assume the lit(i)=line(i:i) is an oversight since i isn't set
>>yet?
> I kind of like statement functions. But they're getting so rare
> that people no longer even recognize them.
Someone posted a program with one a few days ago, or it might
have taken me longer to recognize it.
I got used to them many years ago when I was translating
BASIC programs to Fortran. The only user defined functions
in BASIC are like statement functions.
My favorite statement function story was many years ago about
a benchmark program that did a lot of complicated math using
statement functions and then printed the result. Compiled with
the IBM Fortran H compiler, which expands statement functions
inline and evaluates constant expressions, it compiled very
slow and ran very fast. The whole calculation was done at
compile time!
-- glen
I didn't say I was *overjoyed* with the feature. I just kind of
like it. Yes it's true that there are problems with the current
form of the feature. And because of backward compatibility
constraints you can't even fix those problems. But, the
feature has advantages too. Sure, the declaration should
probably look something like:
Statement_function :: square(x) = x * x
It should not be required (or even possible) to declare
the result type. The function should be inherently generic.
The scope of the dummy argument(s) should be the statement
function only. That is, in the above, the dummy argument X
is just that: a dummy argument. The declaration of X in the
host scope (or lack thereof) should mean nothing to the
use of X here.
All other entities referenced in the function should be host
associated. Finally something Fortran's version of the feature
actually does.
Those (and a few others) are properties statement functions
should have. They already have some of the desired properties.
The use of, say, internal procedures instead is awfully verbose
if all you want is a parameterized abstraction for an expression.
Macros (which some people might regard as similar) don't
do the job at all well (mainly because macro arguments are
"name associated").
So, I kind of like even Fortran's version of the feature. It's
not at all uniformly dismal.
I find them convenient sometimes but I always put ! stmt function
at the end of the line defining one, or ! statement functions
on a line by itself before several, to reduce the chance of misleading
human readers including myself.
-- John Harper, School of Mathematics, Statistics and Computer Science,
Victoria University, PO Box 600, Wellington 6140, New Zealand
e-mail john....@vuw.ac.nz phone (+64)(4)463 5341 fax (+64)(4)463 5045
So how would I tell the compiler that either the result or an
argument was of type character (and of what length), or logical,
or complex, and how would IMPLICIT NONE work?
How do you presently tell the compiler that J*J has the same
type as J? Or that P.le.Q has type logical? You don't. They
are defined that way from the language's definition. Given
the above, the type of SQUARE(T) is whatever the type of
T*T would be. If T has an intrinsic numeric type, the result
is the same type as T. If T has some derived type on which
you have overloaded the "*" operator, the result has whatever
type that operator returns. That's what a generic function
does.
So if your proposal were to be implemented, then would sqmod given by
Statement_function :: sqmod(z) = abs(z)**2
return a complex value if z was complex? Surely it ought to be real
and of the same kind as z if z is complex or real, and integer if z is.
I presume transformational intrinsics would remain forbidden in
statement functions (f95 or f2003 12.5.4 first constraint) for if
Statement_function :: trimconcat(a,b) = trim(trim(a)//b)
were allowed, the length would depend on the actual arguments.
The result type is that which would be expected by applying
the expression defining the statement to the actual argument.
If Z is complex, isn't ABS(Z) REAL? So, isn't that pretty
obviously what would be expected?
This is much why I explicitly mentioned the case of a derived
type argument last time. Given:
Statement_function :: square(x) = x*x
If called as SQUARE(T) the result is whatever the "*" operator
returns when applied to arguments of the type of T.
> I presume transformational intrinsics would remain forbidden in
> statement functions (f95 or f2003 12.5.4 first constraint) for if
>
> Statement_function :: trimconcat(a,b) = trim(trim(a)//b)
>
> were allowed, the length would depend on the actual arguments.
Looks alright to me. The feature is a named, parameterized abstraction
for an expression. The result type, type attributes, and other properties
are whatever that expression would produce if applied to the actual
argument(s). If you wrote:
result = trim(trim(a)//b)
Why would you even remotely suspect the answer to be different
than:
result = trimconcat(a,b)
Why would you *want* the answer to be different than that?
You seem to want some fixed data type, type parameters, and other
attributes to be inherent properties of the function. But that's not the
case with expressions. So why would it be expected to be the case
for named abstractions of expressions? The expression (T*T) doesn't
have some predefined type independent of the type of T. Nor is it
*necessarily* the same as the type of T. It is for intrinsic numeric
types (as I mentioned previously). But not necessarily for all types.
> The result type is that which would be expected by applying
> the expression defining the statement to the actual argument.
> If Z is complex, isn't ABS(Z) REAL? So, isn't that pretty
> obviously what would be expected?
It could be more like C's #define where
#define sq(x) ((x)*(x))
will square any quantity, independent of type.
Then again, if the compiler will run cpp, then you can always
use #define instead of statement functions.
-- glen
As I've already pointed out, macros work not at all well for
this purpose. Consider your version of sq(x) and the following:
answer = sq(f(t))
Using the macro this turns out to be:
answer = ((f(t))*(f(t)))
If the function F has side effects then this most likely violates
the Fortran standard. The evaluation of an entity in a statement
is not allowed to alter the interpretation of any other entity
in the same statement (with some caveates about staements
that have separate control expressions). That hardly works
like functions ought. Just the excessive parenthesis required
are an error prone, easily forgot precaution. As I said, these
problem are mostly due to the fact that macro arguments are
sort of like "name associated" arguments. Genuine function
call semantics are a better choice.
(I wrote)
>>#define sq(x) ((x)*(x))
(snip)
> As I've already pointed out, macros work not at all well for
> this purpose. Consider your version of sq(x) and the following:
> answer = sq(f(t))
> Using the macro this turns out to be:
> answer = ((f(t))*(f(t)))
> If the function F has side effects then this most likely violates
> the Fortran standard.
It violates the standard if you try to use it as an implementation
of statement functions. If it is done explicitly, that is, instead
of statement functions, then the user is expected to worry about
side effects.
> The evaluation of an entity in a statement
> is not allowed to alter the interpretation of any other entity
> in the same statement (with some caveates about staements
> that have separate control expressions). That hardly works
> like functions ought. Just the excessive parenthesis required
> are an error prone, easily forgot precaution. As I said, these
> problem are mostly due to the fact that macro arguments are
> sort of like "name associated" arguments. Genuine function
> call semantics are a better choice.
Some things work better with one, some with the other.
If you do something like:
#define WRITE(x,y) if(debug.or.x.eq.6) WRITE(x,y)
there is no equivalent in terms of functions. There are
even stories of C programs with
#define BEGIN {
#define END }
-- glen
But statement functions were what you were recommending
that macros replace.
> ...] If it is done explicitly, that is, instead
> of statement functions, then the user is expected to worry about
> side effects.
And so, constitutes bad language design.
> Some things work better with one, some with the other.
>
> If you do something like:
>
> #define WRITE(x,y) if(debug.or.x.eq.6) WRITE(x,y)
>
> there is no equivalent in terms of functions. There are
> even stories of C programs with
>
> #define BEGIN {
> #define END }
Yes macros have their uses. A substitute for statement functions
should *never* be one of them.
Ah. I had misunderstood your intentions - sorry. My remote suspicion
arose because in ordinary f95 one must declare the length of a statement
function result in advance, so
print *,'"'//trim(trim(a)//b)//'"'
could give different output from
print *,'"'//trimconcat(a,b)//'"'
But of course trim isn't allowed in a statement function in f95
though it is allowed in an internal function. I tried this test
program getting as near as I could to the above, using both a
statement function and an internal function:
PROGRAM teststmtfunclen
CHARACTER(8):: foo = 'foo', bar = 'bar', trimconcat1, a, b
trimconcat1(a,b) = a(1:len_trim(a))//b ! stmt function
print *, '"'//trim(trim(foo)//bar)//'"'
print *, '"'//trimconcat1(foo,bar)//'"'
print *, '"'//trimconcat2(foo,bar)//'"'
CONTAINS
FUNCTION trimconcat2( a,b)
CHARACTER(*),INTENT(IN)::a,b
CHARACTER(len_trim(trim(a)//b)) trimconcat2
trimconcat2 = trim(trim(a)//b)
END FUNCTION trimconcat2
END PROGRAM teststmtfunclen
Of 5 compilers, one crashed at compile time (I'll send a bug report
because that shouldn't happen even with a non-standard program),
three printed
"foobar"
"foobar "
"foobar"
and one printed
"foobar"
"foobar "
"foobar"
That makes me ask: is my program standard-conforming?
This looks legal to me on superficial examination. Fortran does
sometimes have rules against things that don't make much sense
(well, like not allowing TRIM in a statement function), so you
might be in violation of some arcane requirment that I don't
know or remember. :-(
> Of 5 compilers, one crashed at compile time (I'll send a bug report
> because that shouldn't happen even with a non-standard program),
> three printed
>
> "foobar"
> "foobar "
> "foobar"
>
> and one printed
>
> "foobar"
> "foobar "
> "foobar"
Since the declared length of the statement function is 8
returning 11 characters doesn't seem right. Of course,
11 is the length of the variable BAR plus the length of
the trimmed part of the variable FOO, so my guess is
that the compiler is making some mistake along those
lines.
This is now fixed on 4.3.0. Thanks for the report and for the
Bugzilla entry (pr32613).
We really appreciate the time that people take to file problem
reports. Depending on volunteer effort as we do, we might not be the
quickest but once in Bugzilla they, dare I say it, bug us until they
are done. Being a regression for which I was responsible, I responded
asap.
Thanks
Paul
gfortran 4.2.0 compiled from source dated 20070214 (aka Feb 14 2007).
gfortran 4.3.0 compiled from source dated 20070630 (aka Jun 30 2007).
The problem was fixed yesterday by Paul Thomas
2007-07-05 Paul Thomas <pa...@gcc.gnu.org>
PR fortran/32613
* match.c (gfc_match_do): Reset the implied_index attribute.
You can read the audit trail at
>> Can you submit a bug report? The code works fine with gfortran
>> 4.2.0 20070214, and fails with 4.3.0 20070630. It looks like a
>> possible problem with the statement function.
> Could you post the bug report or if this is it, explain what those largeish
> numbers are after the 4.x.0 ?
Certainly look like a build date yyyymmdd to me...
--
Just for the record, I committed the patch for Al's problem to the
development branch. Overnight binaries of gcc-4.3.0 are fixed.
Paul
> James Giles wrote:
<snip>
> > I kind of like statement functions. But they're getting so rare
> > that people no longer even recognize them.
<snip>
> I got used to them many years ago when I was translating
> BASIC programs to Fortran. The only user defined functions
> in BASIC are like statement functions.
Although BASIC uses the keyword 'DEF' making them easier to recognize.
- formerly david.thompson1 || achar(64) || worldnet.att.net