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

INTENT(OUT) and derived types

Dishaw__Jim
Beginner
1,929 Views
Consider the following code sample:
TYPE foo
  INTEGER :: a
  INTEGER :: b
  CHARACTER(LEN=32) :: c
END TYPE foo

SUBROUTINE bar(fd)
  TYPE(foo), INTENT(OUT) :: fd

  fd%a = 1
END SUBROUTINE bar

SUBROUTINE baz(fd)
  TYPE(foo), INTENT(INOUT) :: fd

  fd%b = 47
  fd%c = 'dog'
  CALL bar(fd)
END SUBROUTINE baz

The behaviour I have observed using the Intel compiler is that after the call to bar from within baz, the fd%c and fd%b members have been cleared (i.e. they do not contain the values 'dog' and 47). The only way to preserve the values is to have INTENT(INOUT) in bar.

I have not delved into the language spec, but the behaviour struck me as unusual until I thought about it some. I can see the logic behind it, however, I want to determine if this behaviour is in the standard or is it compiler dependent. Thanks

0 Kudos
7 Replies
Steven_L_Intel1
Employee
1,929 Views
INTENT(OUT) means that the initial value on entry to the routine becomes undefined. Given that, the actual values can be anything.

The wording in the standard is as follows:

(13) When a procedure is invoked
5 (a) An optional dummy argument that is not associated with an actual argument becomes
6 undefined;
7 (b) A dummy argument with INTENT (OUT) becomes undefined except for any non
8 pointer default-initialized subcomponents of the argument;
9 (c) An actual argument associated with a dummy argument with INTENT (OUT) be-
10 comes undefined except for any nonpointer default-initialized subcomponents of the
11 argument;
12 (d) A subobject of a dummy argument that does not have INTENT (OUT) becomes
13 undefined if the corresponding subobject of the actual argument is undefined; and
14 (e) The result variable of a function becomes undefined except for any of its nonpointer
15 default-initialized subcomponents.

I assume that the real code has a CONTAINS in there somewhere...
0 Kudos
Dishaw__Jim
Beginner
1,929 Views
The real code does have a CONTAINS keyword--I just abbreviated it to keep the post short.

The fact that the INTENT(OUT) in the subroutine bar will change all the members of the derived type in the baz subroutine caught me by suprise. I guess one should only use INTENT(OUT) with a derived type with great care.
0 Kudos
Steven_L_Intel1
Employee
1,929 Views
You should use INTENT(OUT) only if you do not care what happens to the existing values, as they all become undefined (with the exceptions as noted above.) Undefined may or may not mean that they change value, but a correct program would not notice. If you want other fields to be preserved, use INOUT.
0 Kudos
jimdempseyatthecove
Honored Contributor III
1,929 Views

Steve,

Regarding the wording of the standard - could you rephrase it. As worded it does not make sense (to me). Example

(a) An optional dummy argument that is not associated with an actual argument becomes undefined;

Dummy arguments are (to the subroutine or function) symbolic references to one of

a) a reference (address)of a callers argument
b) a value of a callers argument
c) an indication of a missing argument for an optional argument not supplied
d) undefined for an argument not supplied by the caller but specified by the interface
e) trash for arguments supplied that do not conform to interface but somehow manage to reach the subroutine/function

The point is the the argument does not become it is.

Although this may seem like a picky little grammatical issue, the (mis)choice of the word is propagated to the remainder clauses (b, c, d, e) and thus compounds the confusion.

For (13)(b) A dummy argument with INTENT (OUT) becomes undefined except for any non-pointer default-initialized subcomponents of the argument;

The purpose of the INTENT attribute is as a programming aid to help the compiler detect programming errors at compile time. INTENT(OUT) declares that (should the dummy argument refer to a properly supplied argument on call) the initial state of the variable is undefined. As such, if used without first being set, report, at compile time, as an error in programming. INTENT(OUT) does not mean the state of the variable becomes undefined and as suchthe code is required (or free) to muck up the state of the variable without explicit statementsin the code. (i.e. as punishment for not writing good code).

It would be of benefit to some of the forum readers to have some clarification on this issue. My preference would be something along the lines of

Assuming caller supplies actual arguments conforming to calling interface:

INTENT(OUT) - Assert, at compile time, that should the code read from the referenced variable that the code had previouslywritten to the referenced variable. i.e. Assert, at compiletime, that the variable is initialized prior touse. And Warn, if the INTENT(OUT) argument is not written to.

INTENT(IN) - Assume the supplied referenced variable has been initialized and Assert, at compile time, that the code nevermodify the referenced variable.

INTENT(INOUT) -Assume the supplied referenced variable has been initialized. The code is free to modify the value of the referenced variable.

Regarding user defined types and INTENT

When a user defined typeis declared, values of sub-objects not initialized are undefined and remain undefined until initialized.

Compilcating circumstances:

For a single threaded application running on a single processor it is traditional for arguments passed by reference to have the subroutine or function to modify the variable(s) referenced by the argument in-situ (in place). Whenan application evolves to say an MPI type of application (Message Passing Interface) then the environment may necessitate that dummy arguments, specified as callby reference, be passed (to, to/from, from) by a messaging system transparent to the call stateme nt.

As a perfomance optimization, arguments specified with INTENT(OUT) need not be passed to the called subroutine via the messaging system. i.e. no requirement to send uninitialized variables through the messaging system. It should be noted by the programmer, that should the called subroutine not initialize the variables specified with INTENT(OUT), that the values returned willremain undefined, but of particular interest, the undefined values may be different than those contained prior to call. i.e. For INTENT(OUT) uninitialized variables returned from call (via messaging system) are undefined but need not remain thevalues fromprior to call.

What this means is the behavior is (may be) different depending on environment (unified system or message passing system).

Jim Dempsey

0 Kudos
Steven_L_Intel1
Employee
1,929 Views
Jim,

I don't agree with your rephrasing. The standard's wording can sometimes be obtuse, and you often need to go look at several different places in the standard to see what words mean for the purpose of the standard, but in general it "means what it says".

For optional arguments, the idea is that if you have an optional dummy argument not associated with an actual, that dummy argument is undefined on entry to the procedure. So, if you use its value, what happens is undefined. You know, of course, to always protect such references with PRESENT() but the standard needs to specify that the value is undefined.

When the standard says that an INTENT(OUT) dummy and any associated actual argument become undefined, it means exactly that. The dummy starts out undefined, and the actual becomes undefined. If the actual is an allocatable, for example, it gets deallocated automatically.

With an actual that is derived type, what happens depends on whether the type has default initialization specified for any of the components. If it does, those components become defined with the default values, all others become undefined. (and if those components are allocatable, they are deallocated.)

The act of "becoming undefined" does not necessarily mean that the value in memory changes, but it might. The key point here is that a standard-conforming program cannot tell if the value changes or not.

The moral of this story is that you should use INTENT(OUT) only if the called procedure completely defines the dummy argument before returning. If you want any values passed in to survive, you must use INTENT(INOUT) instead.
0 Kudos
jimdempseyatthecove
Honored Contributor III
1,929 Views

Steve,

>> The moral of this story is that you should use INTENT(OUT) only if the called procedure completely defines the dummy argument before returning. If you want any values passed in to survive, you must use INTENT(INOUT) instead.

Fair enough.

However, it is pure insanity to permit code to arbitrarily trash memory. (We all accept that trashing memory is the prerogative of the programmer)

>> If the actual is an allocatable, for example, it gets deallocated automatically.

SUBROUTINE FOO(A)
REAL, ALLOCATABLE :: A(:)
REAL, ALLOCATABLE :: B(:)

! implies an initialization code of
!IF(ALLOCATED(A)) DEALLOCATE(A)
!(initialize B descriptor to unallocated)
! explicit code follows

As for defined types. The question is: is how to identify a member of a defined type as INTENT(OUT) without unintentionally modifying the other (and possibly unknown) members of the drive type?

SUBROUTINE FOO(aFOO)
TYPE(TypeFOO), INTENT(INOUT):: aFOO
INTENT(OUT) :: aFOO%aMember

Is that valid?

Jim Dempsey

0 Kudos
Steven_L_Intel1
Employee
1,929 Views
No, that is not valid. INTENT is an attribute for dummy arguments only, not for components of a derived type. There is no "arbitrary trashing" going on. If you said INTENT(OUT), you told the compiler that the existing contents are to be discarded.

Note that for the ALLOCATABLE example, the dummy arguments have to have INTENT(OUT) in order for the automatic deallocation occur.

You want INTENT(INOUT). Don't try to stretch INTENT(OUT) into something it isn't. The only exception is that if you declare type TypeFOO to have components with default initialization. Then those components will be (re) initialized on entry to the routine.
0 Kudos
Reply