As Steve Lionel's answer, and the comments in my original answer which perhaps sparked this interest, the effects of intent(out)
on the initial state of the dummy argument (and the actual argument) are a way in to answering this question.
intent(inout)
has the dummy argument reflect the value of the actual argument on entry to the procedure. intent(out)
"resets" the dummy argument. In the case of the linked question, this "undefinition" is the cause of the invalid nature of the program.
More precisely, we can say the following things about intent(out)
dummy arguments:
- allocatable actual arguments become deallocated;
- the pointer association of pointer actual arguments becomes undefined;
- for a non-pointer dummy argument any component not default initialized becomes undefined.
The linked question fell foul of the third point by trying to reference such an newly undefined value. However, default initialized components are not undefined, leading us to our first class of valid programs:
implicit none
type t
integer :: x=1
end type t
type(t) :: x=t(0)
call s1(x)
call s2(x)
contains
subroutine s1(x)
type(t), intent(inout) :: x
print*, x%x
end subroutine s1
subroutine s2(x)
type(t), intent(out) :: x
print*, x%x
end subroutine s2
end
Crucially, the default initialization of the component means that x%x
isn't undefined even on entry to s2
, but it takes a potentially different value from the actual argument's component prior to procedure entry.
Coming up with a suitable program with pointer arguments is tricky: a pointer with undefined pointer association status can't be referenced/queried before its pointer association status is redefined.
Which leaves us looking at allocatable components. Unlike with the pointers, where we can't query pointer association status when that's undefined, we can ask about the allocation status. An actual argument corresponding to an intent(out)
dummy is deallocated; with intent(inout)
the allocation status is unchanged:
implicit none
integer, allocatable :: i
allocate (i)
call s1(i); print*, allocated(i)
call s2(i); print*, allocated(i)
contains
subroutine s1(i)
integer, allocatable, intent(inout) :: i
end subroutine s1
subroutine s2(i)
integer, allocatable, intent(out) :: i
end subroutine s2
end
(This is a simpler version of Steve Lionel's example.)
This all shows that it's possible to have differences. Using intent
incorrectly can lead to invalid programs or to significant changes in meaning. Understanding what intent(in)
, intent(inout)
, intent(out)
and no specified intent mean is a crucial part of being a Fortran programmer.