I am new to Fortran and I'd like to understand the differences between these two statments:
logical :: TF
TF = .true.
and:
logical :: TF
data TF/.true./
Please keep the response in more simple to words, I've recenetly moved from Python to this compiled language. Thanks!
Loosely, a DATA statement performs explicit initialization of a variable. An assignment statement gives a variable a value.
These are very different things. You can consider the DATA statement version of this question like
logical, save:: TF=.TRUE.
and see many questions/complaints about how this behaves unexpectedly.
In general, it's worth noting that DATA statement and the "declaration with SAVE" (actually an initialization on declaration) are also (subtly) different. As a beginner, perhaps pretend these initializations don't exist and stick to assignment.
Related
Umm I've came across a problem in Fortran where I need to use Equivalence for a variable which is already declared in a module written by someone else(Probably is dead by now, otherwise I would have contacted him/her).
The variable in the module is of REAL type. And I want to store a INTEGER value in it.
If I do so directly, wrong data gets stored in the REAL type.
I have tried to use equivalence in module, But no luck.
Any Help ?
Well, EQUIVALENCE is an old keyword which should be avoided in modern Fortran because it makes the code misleading, but it has not been eliminated from Fortran standard yet, AFAIK.
However, if you have just the need to store the bit-by-bit representation of a integer in a real variable, I'd rather suggest to use the intrinsic function TRANSFER which literally transfers the binary contents of a variable to a variable of another type without any conversion and without raising errors. So, assuming that your real module variable is x and your integer value is i you can simply do:
x = TRANSFER(i,x)
The second argument could be any real variable, not necessarily x itself, it just gives a hint to the compiler that the result is of real type and it should not be an error to assign it to a real variable.
In fortran 95, if you assign a variable at declaration
integer :: var = 0
it is equivalent to
integer, save :: var = 0
and the variable is therefore preserved after routine execution (is equivalent to static in C speak) and does not get reinitialized when called again. What is the rationale/technical issue behind such (IMHO dangerous) behavior ?
I don't think that there is some rationale behind such behavior.
But as far as I know, Stefano, you used wrong terminology. In your code there is no assignment statement only variable (var) initialization using initialization expression (0).
integer :: var = 0 ! type declaration & initialization
integer :: var ! type declaration
var = 0 ! assignment
So it seems that it was just committee design decision. If we have such expression (with equality sign in type declaration statement) it is initialization not assignment. And initialization takes place only once during program (and not procedures) execution.
However there might be some historical reasons for such decision. Take a look at this thread.
Today such behavior is dangerous because many other widely used languages follows another conventions about initialization/assignment.
Many old FORTRAN 77 and earlier compilers statically allocated all variables. Many programmers relied upon this behavior -- this was technically a bug in their programs since unless they used the "SAVE" qualifier in the declaration (or added a plain SAVE statement to every procedure) the value of the variable was undefined upon reentry to a procedure. But since in those days programs tended to be tied to a particular platform and compiler for years, programmers got away with this. This is a very common "gotcha" in porting legacy FORTRAN 77 code to a modern Fortran >= 90 compilers. Most compilers provide compile-time switches to restore this behavior, such as the fno-automatic option of gfortran. Most likely the committee viewed variables that were initialized in their declaration as very likely to need the SAVE attribute -- in my opinion, a reasonable design decision. I think what is most different from other languages, and easiest to confuse the multi-lingual programmer, is that the initialization is done only once.
The Code
The following MWE describes what I want to use (note that I did not design this, I am merely trying to use someones code, I would not usually use global variables).
PROGRAM MAIN
IMPLICIT NONE
integer :: N
real(8), allocatable :: a(:,:)
N=3
allocate(a(N,3))
a=initialize_array()
CONTAINS
function initialize_array() result(a)
IMPLICIT NONE
real(8) :: a(N,3)
a=1
end function initialize_array
END PROGRAM MAIN
The Problem
gfortran gives an error which reads Error: Variable 'n' cannot appear in the expression at (1), pointing to to the real(8) :: a(N,3) inside the function.
In a subroutine it would work, so what might be the problem here?
The question
Why does ifort (v. 15.0.3) compile this, while gfortran (v. 4.8.4) does not?
As has been commented by others, it is hard to say whether something is clearly allowed: the language is mostly based on rules and constraints giving restrictions.
So, I won't prove that the code is not erroneous (and that gfortran is not allowed to reject it), but let's look at what's going on.
First, I'll object to one thing given by High Performance Mark as this is slightly relevant:
The declaration of an array with a dimension dependent on the value of a variable, such as a(N,3), requires that the value of the variable be known (or at least knowable) at compile time.
The bounds of an explicit shape array need not always be given by constant expressions (what we loosely define as "known/knowable at compile time"): in some circumstances an explicit shape array can have bounds given by variables. These are known as automatic objects (and the bounds given by specification expressions).
A function result is one such place where an automatic object is allowed. In the question's example for the declaration of the function result, N is host associated and forms a specification expression.
Rather than exhausting all other constraints to see that the declaration of a truly is allowed, let's look at how gfortran responds to small modifications of the program.
First, a trimmed down version of the question's code to which gfortran objects.
integer n
contains
function f() result(g)
real g(n)
end function f
end program
The function result for f has the name g. It doesn't matter what we call the function result, so what happens when we call it f?
integer n
contains
function f()
real f(n)
end function f
end program
This compiles happily for me.
What if we frame this first lump in a module instead of a main program?
module mod
integer n
contains
function f() result(g)
real g(n)
end function f
end module
That also compiles.
The natural conclusion: even if gfortran is correct (we've missed some well-hidden constraint) to reject the first code it's either horribly inconsistent in not rejecting the others, or the constraint is really quite strange.
I think this might be an explanation, though like #VladimirF I can't actually either recall or find the relevant section (if there is one) of the standard.
This line
real(8) :: a(N,3)
declares that the result of the function is an array called a. This masks the possibility of the same name referring to the array a by host association. The a inside the function scope is not the a in the program scope.
The declaration of an array with a dimension dependent on the value of a variable, such as a(N,3), requires that the value of the variable be known (or at least knowable) at compile time. In this case giving n in the host scope the attribute parameter fixes the problem. Though it doesn't fix the poor design -- but OP's hands seem tied on that point.
It doesn't surprise me that the Intel compiler compiles this, it compiles all sorts of oddities that its ancestors have compiled over the years for the sake of backwards compatibility.
I only offer this half-baked explanation because experience has taught me that as soon as I do one of the real Fortran experts (IanH, francescalus, (usually) VladimirF) will get so outraged as to post a correction and we'll all learn something.
I am a newbie to Fortran. Please look at the code below:
c main program
call foo(2)
print*, 2
stop
end
subroutine foo(x)
x = x + 1
return
end
In some implementations of Fortran IV, the above code would print a 3. Why is that? Can you suggest an explanation?
How do you suppose more recent Fortran implementations get around the problem?
Help is very much appreciated. Thank You.
The program breaks the language rules - the dummy argument x in the subroutine is modified via the line x = x + 1, but it is associated with something that is an expression (a simple constant). In general, values that result from expressions cannot be modified.
That specific code is still syntactically valid Fortran 2008. It remains a programming error in Fortran 2008 - as it was in Fortran IV/66. This isn't something that compilers are required to diagnose. Some may, perhaps with additional debugging options, and perhaps not till runtime.
Because the program breaks the language rules anything could happen when you run the program. Exactly what depends on the code generated by the compiler. Compilers may have set aside modifiable storage for the value that results from the expression such that it internally looks like a variable (the program might print three and the program carries on), that modifiable storage might be shared across the program for other instances of the constant 2 (suddenly the value of 2 becomes three everywhere!), the storage for the value of the constant might in non-modifiable memory (the program may crash), the compiler may issue an error message, the program may get upset and sulk in its bedroom, the program might declare war on a neighbouring nation - it is a programming error - what happens is unspecified.
As of Fortran 90, facilities were introduced into the language to allow programmers to write new code that is practical for compilers to check for errors such as these (and in some cases compilers are required to check for errors if they are to be regarded as standard conforming).
For the code as presented, the main program and the subroutine are to be regarded as separately compiled - the main program is unaware of the details of the subroutine and vice versa (it is possible that the subroutine could be compiled long after the main program, on a different machine, with the outputs of the two being linked together at some later stage - without fancy link time behaviour or static analysis it is therefore not possible to resolve errors such as this). Language rules are such that when compiling the main program the compiler must implicitly assume the details of the interface of the subroutine based only on the way the subroutine is referenced - inside the main program the subroutine has an implicit interface.
Fortran 90 introduced the concept of an explicit interface, where the compiler is explicitly told what the interface of the subroutine in various ways, and can then check that any reference to the subroutine is consistent with that interface. If a procedure is a module procedure, internal procedure or intrinsic procedure - that interface is automatically realized, alternatively for external subprograms, procedure pointers, etc, the programmer can explicitly describe the interface using an interface block.
In addition, Fortran 90 introduced the intent attribute - a characteristic of a dummy argument of a procedure that is also then a characteristic of the interface for a procedure. The intent of the argument indicates to the compiler whether the procedure may define the argument (it also may implications for default initialization and component allocation status) and hence whether an expression could be a valid actual argument. x in subroutine foo would typically be declared INTENT(INOUT).
Collectively these new language features provide a robust defence against this sort of programming error when using compilers with a basic level of implementation quality. If you are starting with the language then it is recommended that these new features become part of your standard approach - i.e. use implicit none, all procedures should generally be module procedures or internal procedures, use external procedures only when absolutely required, always specify dummy argument intent, use free form source.
In fortran 95, if you assign a variable at declaration
integer :: var = 0
it is equivalent to
integer, save :: var = 0
and the variable is therefore preserved after routine execution (is equivalent to static in C speak) and does not get reinitialized when called again. What is the rationale/technical issue behind such (IMHO dangerous) behavior ?
I don't think that there is some rationale behind such behavior.
But as far as I know, Stefano, you used wrong terminology. In your code there is no assignment statement only variable (var) initialization using initialization expression (0).
integer :: var = 0 ! type declaration & initialization
integer :: var ! type declaration
var = 0 ! assignment
So it seems that it was just committee design decision. If we have such expression (with equality sign in type declaration statement) it is initialization not assignment. And initialization takes place only once during program (and not procedures) execution.
However there might be some historical reasons for such decision. Take a look at this thread.
Today such behavior is dangerous because many other widely used languages follows another conventions about initialization/assignment.
Many old FORTRAN 77 and earlier compilers statically allocated all variables. Many programmers relied upon this behavior -- this was technically a bug in their programs since unless they used the "SAVE" qualifier in the declaration (or added a plain SAVE statement to every procedure) the value of the variable was undefined upon reentry to a procedure. But since in those days programs tended to be tied to a particular platform and compiler for years, programmers got away with this. This is a very common "gotcha" in porting legacy FORTRAN 77 code to a modern Fortran >= 90 compilers. Most compilers provide compile-time switches to restore this behavior, such as the fno-automatic option of gfortran. Most likely the committee viewed variables that were initialized in their declaration as very likely to need the SAVE attribute -- in my opinion, a reasonable design decision. I think what is most different from other languages, and easiest to confuse the multi-lingual programmer, is that the initialization is done only once.