I know about using SAVE for particular subroutines. Am I right in understanding that the above construction simply applies SAVE to everything that is part of the module?
On 2/16/2022 10:34 AM, Arjan wrote:
I know about using SAVE for particular subroutines. Am I right in
understanding that the above construction simply applies SAVE to
everything that is part of the module?
Yes, but it's a no-op, since module variables are now stated to have the
SAVE attribute by default. In earlier standards, there was complicated wording about modules being "active", the way the standard still
describes COMMON from the days of overlays (19.6.6(3)(b)), and we didn't
know of a single F90+ implementation that didn't make all module
variables SAVE anyway.
On 2/16/2022 12:09 PM, Steve Lionel wrote:
On 2/16/2022 10:34 AM, Arjan wrote:
I know about using SAVE for particular subroutines. Am I right in
understanding that the above construction simply applies SAVE to
everything that is part of the module?
Yes, but it's a no-op, since module variables are now stated to have the SAVE attribute by default. In earlier standards, there was complicated wording about modules being "active", the way the standard stillDoes SAVE automatically initialize all listed variables to zero ?
describes COMMON from the days of overlays (19.6.6(3)(b)), and we didn't know of a single F90+ implementation that didn't make all module
variables SAVE anyway.
Thanks,
Lynn
On 2/16/2022 10:34 AM, Arjan wrote:
I know about using SAVE for particular subroutines. Am I right in understanding that the above construction simply applies SAVE to everything that is part of the module?Yes, but it's a no-op, since module variables are now stated to have the
SAVE attribute by default. In earlier standards, there was complicated wording about modules being "active", the way the standard still
describes COMMON from the days of overlays (19.6.6(3)(b)), and we didn't
know of a single F90+ implementation that didn't make all module
variables SAVE anyway.
--
Steve Lionel
ISO/IEC JTC1/SC22/WG5 (Fortran) Convenor
Retired Intel Fortran developer/support
Email: firstname at firstnamelastname dot com
Twitter: @DoctorFortran
LinkedIn: https://www.linkedin.com/in/stevelionel
Blog: https://stevelionel.com/drfortran
WG5: https://wg5-fortran.org
On Wednesday, February 16, 2022 at 5:10:40 PM UTC-5, Lynn McGuire wrote:
On 2/16/2022 12:09 PM, Steve Lionel wrote:
On 2/16/2022 10:34 AM, Arjan wrote:Does SAVE automatically initialize all listed variables to zero ?
I know about using SAVE for particular subroutines. Am I right in
understanding that the above construction simply applies SAVE to
everything that is part of the module?
Yes, but it's a no-op, since module variables are now stated to have the >>> SAVE attribute by default. In earlier standards, there was complicated
wording about modules being "active", the way the standard still
describes COMMON from the days of overlays (19.6.6(3)(b)), and we didn't >>> know of a single F90+ implementation that didn't make all module
variables SAVE anyway.
Thanks,
Lynn
No, but you can initialize variables in the declaration:
module m
implicit none
integer, save :: i = 42
end module m
!
program main
use m
implicit none
print*,"i=",i ! 42
end program main
Thank you Steve. Are variables local to module procedures module variables SAVEd by default?
On 2/17/2022 3:57 PM, jfh wrote:
Thank you Steve. Are variables local to module procedures module variables SAVEd by default?No - those are not module variables.
On Thursday, February 17, 2022 at 3:51:40 PM UTC-8, Steve Lionel wrote:
On 2/17/2022 3:57 PM, jfh wrote:
Thank you Steve. Are variables local to module procedures module variables SAVEd by default?No - those are not module variables.
Can you explain this a little more, maybe with a (one or two line) example?
Does SAVE automatically initialize all listed variables to zero ?
Thanks,
Lynn
No, but you can initialize variables in the declaration:
module m
implicit none
integer, save :: i = 42
end module m
!
program main
use m
implicit none
print*,"i=",i ! 42
end program main
That is a lot of work for the 300,000+ local variables in my software.
gah4 <gah4@u.washington.edu> schrieb:
On Thursday, February 17, 2022 at 3:51:40 PM UTC-8, Steve Lionel wrote:
On 2/17/2022 3:57 PM, jfh wrote:
Thank you Steve. Are variables local to module procedures module variables SAVEd by default?No - those are not module variables.
Can you explain this a little more, maybe with a (one or two line) example?
module foo
integer :: n ! This is a module variable
contains
subroutine bar
integer :: j ! This is not a module variable
end subroutine bar
end module
On 2/18/2022 1:55 AM, pehache wrote:
Writing code is a lot of work. The declaration/initialisation is always
supposed to be a very minor part of any code.
Plus, not all the variables need to be initialised, and not all the
initialised variable need to initialisation to zero.
Which ones need initialization and which ones don't ?
Le 17/02/2022 à 23:37, Lynn McGuire a écrit :
Does SAVE automatically initialize all listed variables to zero ?
Thanks,
Lynn
No, but you can initialize variables in the declaration:
module m
implicit none
integer, save :: i = 42
end module m
!
program main
use m
implicit none
print*,"i=",i ! 42
end program main
That is a lot of work for the 300,000+ local variables in my software.
Writing code is a lot of work. The declaration/initialisation is always supposed to be a very minor part of any code.
Plus, not all the variables need to be initialised, and not all the initialised variable need to initialisation to zero.
On 2/16/2022 9:36 PM, Beliavsky wrote:.
On Wednesday, February 16, 2022 at 5:10:40 PM UTC-5, Lynn McGuire wrote:
On 2/16/2022 12:09 PM, Steve Lionel wrote:
On 2/16/2022 10:34 AM, Arjan wrote:Does SAVE automatically initialize all listed variables to zero ?
I know about using SAVE for particular subroutines. Am I right in
understanding that the above construction simply applies SAVE to
everything that is part of the module?
Yes, but it's a no-op, since module variables are now stated to have the >>> SAVE attribute by default. In earlier standards, there was complicated >>> wording about modules being "active", the way the standard still
describes COMMON from the days of overlays (19.6.6(3)(b)), and we didn't >>> know of a single F90+ implementation that didn't make all module
variables SAVE anyway.
Thanks,
Lynn
No, but you can initialize variables in the declaration:
module m
implicit none
integer, save :: i = 42
end module m
!
program main
use m
implicit none
print*,"i=",i ! 42
end program main
That is a lot of work for the 300,000+ local variables in my software..
On Saturday, February 19, 2022 at 6:48:19 AM UTC+11, Lynn McGuire wrote:
On 2/18/2022 1:55 AM, pehache wrote:
Le 17/02/2022 à 23:37, Lynn McGuire a écrit :
Does SAVE automatically initialize all listed variables to zero ?
Thanks,
Lynn
No, but you can initialize variables in the declaration:
module m
implicit none
integer, save :: i = 42
end module m
!
program main
use m
implicit none
print*,"i=",i ! 42
end program main
That is a lot of work for the 300,000+ local variables in my software. >>>>
.Writing code is a lot of work. The declaration/initialisation is alwaysWhich ones need initialization and which ones don't ?
supposed to be a very minor part of any code.
Plus, not all the variables need to be initialised, and not all the
initialised variable need to initialisation to zero.
Initialize them all.
On 2/18/2022 1:55 AM, pehache wrote:.
Le 17/02/2022 à 23:37, Lynn McGuire a écrit :
Does SAVE automatically initialize all listed variables to zero ?
Thanks,
Lynn
No, but you can initialize variables in the declaration:
module m
implicit none
integer, save :: i = 42
end module m
!
program main
use m
implicit none
print*,"i=",i ! 42
end program main
That is a lot of work for the 300,000+ local variables in my software.
Writing code is a lot of work. The declaration/initialisation is always supposed to be a very minor part of any code.
Plus, not all the variables need to be initialised, and not all the initialised variable need to initialisation to zero.Which ones need initialization and which ones don't ?
On 2/18/2022 7:42 PM, Robin Vowels wrote:.
On Saturday, February 19, 2022 at 6:48:19 AM UTC+11, Lynn McGuire wrote:
On 2/18/2022 1:55 AM, pehache wrote:
Le 17/02/2022 à 23:37, Lynn McGuire a écrit :
Does SAVE automatically initialize all listed variables to zero ? >>>>>>
Thanks,
Lynn
No, but you can initialize variables in the declaration:
module m
implicit none
integer, save :: i = 42
end module m
!
program main
use m
implicit none
print*,"i=",i ! 42
end program main
That is a lot of work for the 300,000+ local variables in my software. >>>>
Except the subroutine and function arguments..Writing code is a lot of work. The declaration/initialisation is always >>> supposed to be a very minor part of any code.Which ones need initialization and which ones don't ?
Plus, not all the variables need to be initialised, and not all the
initialised variable need to initialisation to zero.
Initialize them all.
On 2/18/2022 1:55 AM, pehache wrote:
Le 17/02/2022 à 23:37, Lynn McGuire a écrit :
Does SAVE automatically initialize all listed variables to zero ?
Thanks,
Lynn
No, but you can initialize variables in the declaration:
module m
implicit none
integer, save :: i = 42
end module m
!
program main
use m
implicit none
print*,"i=",i ! 42
end program main
That is a lot of work for the 300,000+ local variables in my software.
Writing code is a lot of work. The declaration/initialisation is
always supposed to be a very minor part of any code.
Plus, not all the variables need to be initialised, and not all the
initialised variable need to initialisation to zero.
Which ones need initialization and which ones don't ?
"SAVE" and "initialise" are very different.understand the scare campaign of COMMON or MODULE going out of scope.
I have assumed SAVE for global data is not necessary. I have mostly assumed both COMMON and MODULE to have global scope, except for the use of overlays on pre extended memory PC's, which I have mostly forgotten and I hope is forgotten. I don't
MODULE combined with derived types is a great way to define the memory data structures, which can feature initialised data..
I avoid SAVE for local variables/arrays, which is incompatible with recursive or OpenMP approaches.
Initialise, especially default initialise can be very dangerous/expensive(?), as it demands memory be allocated to any initialised arrays in a Module/Common at startup. It can (has) also produce a very large .exe, depending on the linker approach.
I prefer to initialise variables and arrays as they are being used. When I was taught FORTRAN,
it was an error to use an un-initialised variable,
so assuming default initialisation is wrong to me.data as special, is something that the modern MODULE approach does not highlight.
I avoid default initialisation of arrays.
BLOCK DATA subprograms had a use as they documented which common variables were initialised. I thing these COMMON were allocated a different address class during linking, although this approch has been lost. This identification of initialised module
Default Initialising large arrays will eat memory. I have seen compilers that offer default initialising of large allocatable arrays. This removes any strategy of minimising/delaying physical memory usage, (which is not always an issue)
Is there a 2 GByte limit of initialised variables with some linkers ?
"SAVE" and "initialise" are very different.
I have assumed SAVE for global data is not necessary. I have mostly assumed both COMMON and MODULE to have global scope, except for the use of overlays on pre extended memory PC's, which I have mostly forgotten and I hope is forgotten.
I don't understand the scare campaign of COMMON or MODULE going out of scope.
MODULE combined with derived types is a great way to define the memory data structures, which can feature initialised data.
I avoid SAVE for local variables/arrays, which is incompatible with recursive or OpenMP approaches.
Initialise, especially default initialise can be very dangerous/expensive(?), as it demands memory be allocated to any initialised arrays in a Module/Common at startup. It can (has) also produce a very large .exe, depending on the linker approach.
I prefer to initialise variables and arrays as they are being used. When I was taught FORTRAN, it was an error to use an un-initialised variable, so assuming default initialisation is wrong to me.
I avoid default initialisation of arrays.
BLOCK DATA subprograms had a use as they documented which common variables were initialised.
I thing these COMMON were allocated a different address class during linking, although this approch has been lost. This identification of initialised module data as special, is something that the modern MODULE approach does not highlight.
Default Initialising large arrays will eat memory.
I have seen compilers that offer default initialising of large allocatable arrays.
This removes any strategy of minimising/delaying physical memory usage, (which is not always an issue)
Is there a 2 GByte limit of initialised variables with some linkers ?
I have assumed SAVE for global data is not necessary. I have mostly assumed both COMMON and MODULE to have global scope, except for the use of overlays on pre extended memory PC's, which I have mostly forgotten and I hope is forgotten. I don'tunderstand the scare campaign of COMMON or MODULE going out of scope.
MODULE combined with derived types is a great way to define the memory data structures, which can feature initialised data.
On 2/20/22 1:23 AM, JCampbell wrote:
"SAVE" and "initialise" are very different.I think global scope and whether data is required to retain old values
I have assumed SAVE for global data is not necessary. I have mostly assumed both COMMON and MODULE to have global scope, except for the use of overlays on pre extended memory PC's, which I have mostly forgotten and I hope is forgotten.
are two different issues, related, but different.
I don't understand the scare campaign of COMMON or MODULE going out of scope.Common and modules have global scope in the sense that a program can
access them at any level in the subprogram calling sequence. However, it
is not until the recent fortran revisions that they were required to
retain their old values globally. That was why SAVE was introduced for
common blocks in f77, in order to define exactly when the previous
values were required to be saved and when they weren't. So it was not
really "scare tactics", it was just recognizing the semantics of the
language over the last 45 years.
MODULE combined with derived types is a great way to define the memory data structures, which can feature initialised data.Yes, there are times when SAVE is necessary, and there are times when
I avoid SAVE for local variables/arrays, which is incompatible with recursive or OpenMP approaches.
SAVE should be avoided.
Initialise, especially default initialise can be very dangerous/expensive(?), as it demands memory be allocated to any initialised arrays in a Module/Common at startup. It can (has) also produce a very large .exe, depending on the linker approach.I don't disagree with this. There are times when fortran initialization should be avoided and assignments should be used instead (to
I prefer to initialise variables and arrays as they are being used. When I was taught FORTRAN, it was an error to use an un-initialised variable, so assuming default initialisation is wrong to me.
I avoid default initialisation of arrays.
"initialize" entities using the common meaning of the term).
However, a nice feature would be the ability to initialize allocatable scalars and arrays. This would eliminate a common class of program
errors, and simplify the use of allocatable entities.
On Sunday, February 20, 2022 at 1:14:33 PM UTC-5, Ron Shepard wrote:[...]
On 2/20/22 1:23 AM, JCampbell wrote:
However, a nice feature would be the ability to initialize allocatable
scalars and arrays. This would eliminate a common class of program
errors, and simplify the use of allocatable entities.
You can write
allocate(x(n), source = 0.0)
or
x = zeros(n)
where zeros is an easy function to define. What additional functionality do you want?
On 2/20/22 2:32 PM, Beliavsky wrote:
..
Then when an instance of that type is declared, the programmer knows
that both components have initial values and in particular that the
array component is always in an allocated state, so it is never
necessary to test that allocation status before using or modifying it.
It would be useful to initialize allocatable arrays, character strings,
and user defined types, sometimes to have zero size, sometimes to have nonzero size with initial values.
This has been discussed here in clf before, and the main objection is
that allocatable data typically exists in a heap which is not available until run time. I understand that argument, but that doesn't seem to be serious enough to override all of the obvious advantages of this feature
to the programmer. ..
Yes, there are times when SAVE is necessary, and there are times when
SAVE should be avoided.
On 2/20/22 2:32 PM, Beliavsky wrote:
On Sunday, February 20, 2022 at 1:14:33 PM UTC-5, Ron Shepard wrote:[...]
On 2/20/22 1:23 AM, JCampbell wrote:
However, a nice feature would be the ability to initialize allocatable
scalars and arrays. This would eliminate a common class of program
errors, and simplify the use of allocatable entities.
You can write
allocate(x(n), source = 0.0)
or
x = zeros(n)
where zeros is an easy function to define. What additional functionality do you want?I was talking about fortran initialization in that sentence. Your
examples are initialization in the common meaning of the word with executable statements.
To show one potential problem, your first statement above will fail if
x(:) is already allocated, so it might be necessary to test the
allocation status first. Then suppose the above statement might need to
be executed in many places in the code, both the allocation status query
and the allocate() statement need to be coupled and always occur
together. The second form does not need the status query, of course,
because allocation on assignment works in either case, but there are situations where the allocate() statement is necessary and the
assignment cannot be used.
For example, for a default initialization situation, the derived type
might be defined as
type xxx
integer :: n = 0
integer, allocatable :: array(0:0)=[0]
end type xxx
Then when an instance of that type is declared, the programmer knows
that both components have initial values and in particular that the
array component is always in an allocated state, so it is never
necessary to test that allocation status before using or modifying it.
It would be useful to initialize allocatable arrays, character strings,
and user defined types, sometimes to have zero size, sometimes to have nonzero size with initial values.
This has been discussed here in clf before, and the main objection is
that allocatable data typically exists in a heap which is not available until run time. I understand that argument, but that doesn't seem to be serious enough to override all of the obvious advantages of this feature
to the programmer.
$.02 -Ron Shepard
Most of the time I use allocatable or allocatable component of a user defined type in a procedure where they are dummy arguments with intent(out) or local variables. So they are always unallocated at the beginning of the procedure. Adding thereallocation on assignment, I rarely need to check their allocation status or deallocate them.
On 2/23/22 6:14 AM, Edmondo Giovannozzi wrote:reallocation on assignment, I rarely need to check their allocation status or deallocate them.
[...]
Most of the time I use allocatable or allocatable component of a user defined type in a procedure where they are dummy arguments with intent(out) or local variables. So they are always unallocated at the beginning of the procedure. Adding the
Yes, that was my point. They are always unallocated at the beginning.
because there is currently no way to declare them to be in an allocated state or an allocated state with values. If that were possible, then
there are many situations where that would simplify the logic of the program.
Also, with reallocation on assignment, you lose control of the ability
to specify the lower bound of the array. You must use an allocate() statement for that, and the array in the allocate statement must be deallocated, otherwise it is an error. Similarlly, the array must be allocated if used in a deallocate statement, otherwise it is an error.
So the current situation is an intertangled mess of conditions and constraints, all leading to a lot of complicated code logic.
I'm not a compiler writer, so maybe this is all too difficult to do, but
it seems like from the programmer's perspective things would be much
easier if you could initialize allocatable entites to have an allocated state, possibly with values, if you could allocate() an entity that is already allocated (perhaps by specifying an optional keyword to allow
the prior deallocation), if you could deallocate() an entity that is
already deallocated, and if you could control the lower bounds of allocatable arrays during allocate-on-assignment.
As for never needing to deallocate an allocatable entity, there are many situations where that is necessary, in addition to reallocating arrays
to have different sizes and/or bounds. The move_alloc() intrinsic is
useful for the size change, but there is no efficient way to change the bounds of an allocatable array while leaving its extents the same in the various dimensions. That should be an operation that requires
essentially no computational effort, but at present requires the
unnecessary copying of array data.
I'm not a compiler writer, so maybe this is all too difficult to do, but
it seems like from the programmer's perspective things would be much
easier if you could initialize allocatable entites to have an allocated state, possibly with values, if you could allocate() an entity that is already allocated (perhaps by specifying an optional keyword to allow
the prior deallocation), if you could deallocate() an entity that is
already deallocated, and if you could control the lower bounds of
allocatable arrays during allocate-on-assignment.
On Wednesday, February 23, 2022 at 10:45:27 PM UTC-8, Ron Shepard wrote:.
(snip)
I'm not a compiler writer, so maybe this is all too difficult to do, butPersonally I think it is strange, but array expressions always have a lower bound of 1. Since allocate on assignment uses the bounds of the
it seems like from the programmer's perspective things would be much
easier if you could initialize allocatable entites to have an allocated state, possibly with values, if you could allocate() an entity that is already allocated (perhaps by specifying an optional keyword to allow
the prior deallocation), if you could deallocate() an entity that is already deallocated, and if you could control the lower bounds of allocatable arrays during allocate-on-assignment.
expression being assigned, the lower bound will always be 1.
If you want a different lower bound, then you ALLOCATE it first.
If you want to ALLOCATE already allocated arrays, or DEALLOCATE
unallocated arrays, without any error message, then put STAT=
on, and ignore the value.
I suppose it would be slightly more convenient if you could put
STAT= without a variable, showing that you were ignoring it, but
otherwise just name your variable IGNORE. (Convieniently
already an INTEGER!)
Also, with reallocation on assignment, you lose control of the ability.
to specify the lower bound of the array. You must use an allocate()
statement for that, and the array in the allocate statement must be
deallocated, otherwise it is an error. Similarlly, the array must be
allocated if used in a deallocate statement, otherwise it is an error.
So the current situation is an intertangled mess of conditions and
constraints, all leading to a lot of complicated code logic.
Really? The code is linearly executed.
.
You can write:
deallocate (x) ; allocate (x); x = 1
If you're testing whether x is already allocated, you can put that on the same line too.
On Wednesday, February 23, 2022 at 10:45:27 PM UTC-8, Ron Shepard wrote:
(snip)
I'm not a compiler writer, so maybe this is all too difficult to do, but
it seems like from the programmer's perspective things would be much
easier if you could initialize allocatable entites to have an allocated
state, possibly with values, if you could allocate() an entity that is
already allocated (perhaps by specifying an optional keyword to allow
the prior deallocation), if you could deallocate() an entity that is
already deallocated, and if you could control the lower bounds of
allocatable arrays during allocate-on-assignment.
Personally I think it is strange, but array expressions always have a lower bound of 1. Since allocate on assignment uses the bounds of the
expression being assigned, the lower bound will always be 1.
If you want to ALLOCATE already allocated arrays, or DEALLOCATE
unallocated arrays, without any error message, then put STAT=
on, and ignore the value.
On 2/24/22 9:52 AM, Robin Vowels wrote:.
Hmm?Also, with reallocation on assignment, you lose control of the ability.
to specify the lower bound of the array. You must use an allocate()
statement for that, and the array in the allocate statement must be
deallocated, otherwise it is an error. Similarlly, the array must be
allocated if used in a deallocate statement, otherwise it is an error.
So the current situation is an intertangled mess of conditions and
constraints, all leading to a lot of complicated code logic.
Really? The code is linearly executed.
.
You can write:
deallocate (x) ; allocate (x); x = 1
If you're testing whether x is already allocated, you can put that on the same line too.
As I pointed out, the test for allocation is necessary prior to this
sequence of statements,
If the scalar x.
is already allocated and is some intrinsic type, then.
this sequence is a very expensive way to do the simple assignment
x = 1.
If x is an array, then there needs to be an upper and perhaps a lower
bound specified.
Personally I think it is strange, but array expressions always have a lower bound of 1. Since allocate on assignment uses the bounds of the
expression being assigned, the lower bound will always be 1.
Yes, here is a short program that demonstrates that. Try to predict what
the printed values will be before running it. Programmers often miss one
or more of the cases.
The same consideration would apply to allocate() for several work arrays
each with unknown prior allocation status. In this case, I think the appropriate semantics would be to conditionally allocate each array,
first checking both its allocation status and also its currently
allocated lower and upper bounds. In the latter case, if the extents
match, but the bounds differ, then only the bounds should be changed, avoiding the potentially expensive allocation process and also
preserving the content. Currently, there is no efficient way to change
the bounds of an allocated array while keeping its contents intact, or keeping pointers to that target array defined while changing its bounds.
Try[...]
if (allocated(x)) deallocate (x); allocate (x); x = 1
if scalar x is already allocated, you just write an assignment statement.
Try x = 1
If x is an array, then there needs to be an upper and perhaps a lower.
bound specified.
Not necessarily.
Can you explain this a little more, maybe with a (one or two line) example?
module foo
integer :: n ! This is a module variable
contains
subroutine bar
integer :: j ! This is not a module variable
end subroutine bar
end module
But how about SUBMODULE, which I don't see any examples of in the standard.
If you put a module or submodule inside subroutine bar, then how does it work?
Sysop: | Keyop |
---|---|
Location: | Huddersfield, West Yorkshire, UK |
Users: | 159 |
Nodes: | 16 (0 / 16) |
Uptime: | 99:19:24 |
Calls: | 3,209 |
Files: | 10,563 |
Messages: | 3,009,786 |