Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
29345 Discussions

Question on Initializing a variable based on a derived type

lklawrie
Beginner
1,670 Views

Derived type:

TYPE MixerData
LOGICAL :: Exists=.false. ! True if there is a mixer (only 1 allowed per loop)
CHARACTER(len=MaxNameLength) :: Name=' ' ! Name of the mixer
INTEGER, ALLOCATABLE, DIMENSION(:) :: NodeNumIn ! Node number for the inlet to the mixer
END TYPE MixerData

Initialization:

TYPE (MixerData) :: MyMixer=MixerData(.false.,' ', ???)

What does one put where the ??? are for an unallocated array or can you not do that?

Linda

0 Kudos
13 Replies
Steven_L_Intel1
Employee
1,670 Views
You are allowed to use NULL() there, but why do this when you have already specified default initialization for the type? You could also use the keyword form of a type constructor and not specify the value for NodeNumIn.
0 Kudos
lklawrie
Beginner
1,670 Views

Null() generates an error. What is the keyword specification? e.g., Exists=.false.? I have not seen this in fortran specifications.

If you make a variable based on a derived type (not allocated), some compilers don't seem to like just a simple variable without saying SAVE. Others accept it. Just trying to satisfy many compilers.

Linda

0 Kudos
Steven_L_Intel1
Employee
1,670 Views
Ok, I got a bit ahead of myself.

First, it seems the keyword syntax in structure constructors is a F2003 feature we don't yet support. (I will have to verify that when I get back to the office on Monday, I can see that it does not work.)

You cannot use an initialization expression to initialize a derived type containing an allocatable or pointer. You can provide default initialization in the type declaration which you did already - there's no point in saying it again.

You DO need to add SAVE to the declaration of MixerData if you want it saved - default initialization in a derived type does not imply SAVE and the variable will otherwise get reinitialized on each entry to the routine. This is a tricky point of the language that some compilers may not get right (in the past we didn't either, but we do now.)

0 Kudos
lklawrie
Beginner
1,670 Views

To clarify, the MyMixer variable is a module variable, not a routine variable. Yes, I would add a SAVE automatically to the routine level variable. Some compilers insist on that in the module level as well.

Thanks for looking.

Linda

0 Kudos
Steven_L_Intel1
Employee
1,670 Views
Technically, you should add SAVE to the module variable if there could ever be a chain of active routines where none of them USE the module. Doesn't hurt.
0 Kudos
lklawrie
Beginner
1,670 Views

Not sure about IVF (I'm not sure what compiler options I have turned on there) -- CVF complains if you put a SAVE in a module level...

"Warning: the SAVE attribute may only be declared for objects in a subprogram."

Linda

0 Kudos
Steven_L_Intel1
Employee
1,670 Views
That's a CVF bug - I remember it.
0 Kudos
jimdempseyatthecove
Honored Contributor III
1,670 Views

>> Technically, you should add SAVE to the module variable if there could ever be a chain of active routines where none of them USE the module.

???

If you have a chain of active routines where none of them are USEing the module then there is no reference and therefore no requirement to initialize nor save that which is not referenced.

If any of a chain of active (or inactive)routines within an assembly contain a USE for a module, thus linking in the USEglobal data (if declared) and the contains functions (if declared), and the accompanying initialization code if defined and declared. Once loaded and initialized it is persistant with the execuitable.

That said, if you were to declare an instance of a derrived type within a subroutine (as opposed to inside the module dataportion of the module) then SAVE would be requied to maintain persistance.

Jim Dempsey

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,670 Views

Linda,

If you are unable to specify no allocation and if you do not wish to waste memory on allocating your working storage when not require then why not allocate to an unusable size. e.g. allocate to say 1. And then in your code where test for ALLOCATED follow it with a test for SIZE of 1 (as an indication of not allocated to the correct size).

Jim Dempsey

0 Kudos
Steven_L_Intel1
Employee
1,670 Views
Jim,

I understand your confusion, but the standard (F2003 here) sez:

(3) When execution of an instance of a subprogram completes,
(a) its unsaved local variables become undefined,
(b) unsaved variables in a named common block that appears in the subprogram become undefined if they have been defined or redefined, unless another active scoping unit is referencing the common block,
(c) unsaved nonfinalizable local variables of a module become undefined unless another active scoping unit is referencing the module, and
(d) unsaved finalizable local variables of a module may be finalized if no other active scoping unit is referencing the module following which they become undefined.

NOTE 16.18
A module subprogram inherently references the module that is its host. Therefore, for processors that keep track of when modules are in use, a module is in use whenever any procedure in the module is active, even if no other active scoping units reference the module; this situation can arise if a module procedure is invoked via a procedure pointer, a type-bound procedure, or a companion processor.


I don't know of any implementation that would actually lose the value of a module variable that is not SAVEd, but the standard says it could happen. Note that the standard has said this about COMMON blocks "forever" and this WAS a real possibility back in the era of "overlays" where sections of a program were brought in from disk as needed wiping out existing memory.

I'll admit that even I don't go adding SAVE to my module variables, but if it was possible for a module to go out-of-scope, I should do so if I wanted to ensure that the variable remained defined. (Note also that just because the value is undefned that doesn't mean it changes value - only that you can no longer depend on the value.)
0 Kudos
jimdempseyatthecove
Honored Contributor III
1,670 Views

Steve,

Sez this:

>> (c) unsaved nonfinalizable local variables of a module become undefined unless another active scoping unit is referencing the module, and

This would seem to refer specifically tolocal variables within subroutines and functions in the CONTAINS section (but they you couldn't access them via USE in an application).

>>a module is in use whenever any procedure in the module is active

The keyword above is procedure (process). A procedure has birth, life, death. Where the USE data gets constructed during the birth and destroyed during the death. Typically an application is but one procedure (process)and therefore the USE data is persistent through-out the application. A procedure (on most systems) has one virtual address space (which may be spread across several processors).

This said, some "applications" consist of collections of procedures with one procedure typically acting as a control procedure but it could also be setup without designated controlling procedure. Each of the procedures have separate virtual address spaces, however with mapping techniques such as a Memory Mapped Files it is possible that portions of the (or each) process reference common data (potentially the data within the USEed module). Under this circumstance it is possible for the procedure to die while the application lives. I think this is what NOTE 16.18 is referring to.

There is also the situation where an application proceedure (process code), built to run stand alone, is loaded within one virtual addres space together with other procedures, also built to run stand-alone, where the controlling application calls the C runtime initialition coded of each procedure as opposed to the _main.

Jim Dempsey

0 Kudos
Steven_L_Intel1
Employee
1,670 Views
Jim,

In this context, "local variables of a module" means module-level variables, not those within module procedures (which are not module variables.)

The note I cited applies to the F2003 feature of procedure pointers, which Intel Fortran does not yet support. It's saying that a compiler can't rely on simple lexical scope to determine where a module is or is not in use.
0 Kudos
jimdempseyatthecove
Honored Contributor III
1,670 Views

>>It's saying that a compiler can't rely on simple lexical scope to determine where a module is or is not in use.

Precisely.

This is similar to potential problems of pointer to array

aPointer = aFuncThatAllocates()
call SomethingThatDeallocatesAbove()
aPointer.member=boink

When you have procedure pointers (where multiple procedures share the same virtual address space) you would have a similar problem (pseudo code)

ProcedureReference = SpawnProcedure()
pDerivedType => ProcedureReference.GetModuleDataReference()
... ! procedure terminates here and module data goes away !
pDerivedType.member = boink

Jim

0 Kudos
Reply