I am wondering how this is interpreted by Fortran compilers (they seem to accept it):
module savemodule
implicit none
type :: savetype
integer :: savevariable = 1
end type savetype
end module savemodule
use savemodule
implicit none
type(savetype) :: s1, s2
s1 % savevariable = 2
s2 % savevariable = 2
print *, s1 % savevariable, s2 % savevariable
end
If on the other hand I add a save attribute to
integer, save :: savevariable = 1
Compilers start to complain that this is not allowed. However, I believe save is implicitly added to the original version too. What is more strange is that with the “implicit save” attribute the code performs worse. There is a code that had initialization this way and the performance is much worse in loop with overloaded multiplication and sum of a derived type. When the initialization was moved to main program statements, the code was as performant as the comparable code with real numbers (compiled with gfortran). So clearly save is doing something in the type declaration.
And the compiler is right. There’s a fundamental difference between the initialization of a variable and the initialization of a component in a derived type: in the former case this is an initialization at compile time, once for the whole execution of the program, and in the latter case this is an initialization at runtime, each time an instance of the derived type is created.
Nope. The save attribute has actually no sense for a derived type component, as nothing is instantiated at this point, this is just the description of what the type is.
One would need to see the code to understand and possibly explain what really happens.
I thought first that save doesn’t make sense in type declaration statement. But I got a bit derailed because of
my observation of initialization of variables upon declaration statements of derived type. Btw. When there are more variables with initialization, the worse performance gets (compared to a similar situation with initializations at main program). I should mention that link-time optimization was used (-fwhole-file).
Implicit save in variable declaration when initialized
So i started thinking that there might be some special meaning when initialization is used at type declaration statements.
I guess I am trying to understand the difference between initializing a variable at the derived type declaration statements (the first code I posted) and initialization only at the main program:
module savemodule
implicit none
type :: savetype
integer :: savevariable
end type savetype
end module savemodule
use savemodule
implicit none
type(savetype) :: s1, s2
s1 % savevariable = 2
s2 % savevariable = 2
print *, s1 % savevariable, s2 % savevariable
end
When you specify an initial value for a component, that is called default initialization. As others have explained, nothing is actually initialized at that time because there is no variable of that type to initialize. It just tells the compiler that when variables are declared of that type elsewhere, those will be the initial values. The main program has nothing to do with this, the same thing happens everywhere.
If you want to initialize your variables upon declaration, then you would do something like
type(savetype), save :: s1=savetype(2), s2=savetype(2)
The save attribute there is the default for initialized variables, but I usually specify it anyway to tell human readers of the code what is happening. I think most programmers believe it was a mistake for fortran to make that the default, and I don’t want to appear to support that bad choice.
If you have both default initialization and actual initialization, as above, then the actual initialization overrides the default initialization.
[edit] I wanted to add that when the values are set in assignment statements, that is not initialization in the fortran sense. Those are just normal assignments. It would be difficult to say exactly which parts are done at compile time and which at run time for this code. It is simple enough that the whole thing could be reduced to just the equivalent of
print *, 2, 2
with all the variations that have been discussed. A more interesting set of questions is what happens in the various cases when the print statement is in a subroutine that is compiled separately from its calling program. Then you can ask questions about when the value is set, if the variable is saved between calls, or if the value is reset anew each call.
I think the mystery is solved: Thanks to the responses here I started thinking that the default initialization takes place in our code each time the overloaded binary operation is executed. And if that is in a for loop, it happens every time. Consider the following:
do i=1,n
a(i) = b(i)*c(i)
end do
In case b and c are vectors of a derived type and the (*) overload instanciates a derived type that has some default initializations, then that happens on every loop cycle. Thus it performs worse than a deriverd type without default initializations. Moreover, a derived type with no default initializations should perform equally well compared to real type vectors if the overloaded ultimate multiplied types are real. Given that compiler knows how to optimize that.
This sounds plausible. You might be able to tell if your conjecture is correct by examining the intermediate code (or the assembler code) output for the two cases, with and without initialization. With gfortran, try -fdump-parse-tree. I would guess that simply initializing an integer component to a value within existing memory would not affect performance much. But if a derived type temporary is allocated anew for each pass through the loop for the initialization case, that could affect performance.