3

Suppose an dummy argument is modified in a subroutine, and the subroutine doesn't care about its initial value. For a scalar of the standard numerical types (no components), intent(out) would be correct, right?

Now, if the dummy argument is allocatable and the subroutine depends on its allocation status, or if it has components that are not modified by the subroutine but should maintain their initial values (i.e. not become undefined), or, similarly, if it's an array and not all elements are set in the subroutine... Then the proper intent would be intent(inout).

My question is what happens if the dummy argument is an assumed-size array (dimension(*))? Assuming that not all elements are modified in the subroutine and one wants the other elements to retain their initial values, would intent(out) be appropriate? My reasoning is that the subroutine doesn't "know" the size of the array, so it cannot make the elements undefined as it can with a fixed-size array.

Does the standard say anything about this or are compilers free to "guess" for example that if I set A(23) = 42, then all elements A(1:22) can be made undefined (or NaN, or garbage...)?

Note: When I say "retain their initial values", I mean the values in the actual argument outside the subroutine. The subroutine itself doesn't care about the values of these elements, it never reads them or writes them.

Jellby
  • 2,360
  • 3
  • 27
  • 56
  • 2
    A value becoming undefined is not related to the compiler setting to NaN (or other value), but what you as a programmer can rely on. If you need "initial values" then you can't use `intent(out)` even if a compiler won't actually "reset" those values. That's what Fortran specifies, not what you can "get away with". (More detail in the linked, but if that doesn't help you please [edit] the question and we can reevaluate duplicate.) – francescalus Apr 17 '21 at 11:05
  • @francescalus I understand that I can't rely on these "initial values" inside the subroutine if I use `intent(out)`. My question is about what happens to the values of the actual argument outside the subroutine. I added a "note" to the question, hopefully that's enough? – Jellby Apr 17 '21 at 11:34

1 Answers1

0

Another question looks at what "becomes undefined" means in terms of the dummy argument. However, exactly the same aspects apply to the actual argument with which the dummy argument is associated: it becomes undefined.

The Fortran standard itself gives a note on this aspect "retaining" untouched values (Fortran 2018, 8.5.10, Note 4):

INTENT (OUT) means that the value of the argument after invoking the procedure is entirely the result of executing that procedure. If an argument might not be redefined and it is desired to have the argument retain its value in that case, INTENT (OUT) cannot be used because it would cause the argument to become undefined

That note goes on further to consider whether intent(inout) would be appropriate for when the procedure doesn't care about values:

however, INTENT (INOUT) can be used, even if there is no explicit reference to the value of the dummy argument.

That the array is assumed-size plays no part in the undefinition of the actual and dummy arguments. Again, to stress from my answer to the other question: "undefined" doesn't mean the values are changed. As the compiler has no required action to perform to undefine values, it doesn't need to work out which values to undefine: with an assumed-size dummy argument the procedure doesn't know how large it is, but this doesn't excuse the compiler from "undefining" it, because there's nothing to excuse.

You may well see that the "undefined" parts of the assumed-size array remain exactly the same, but intent(inout) (or no specified intent) remains the correct choice for a compliant Fortran program. With copy-in/copy-out mechanics with intent(out), for example, the compiler wouldn't be obliged to ensure the copy is defined and that junk isn't copied back.

Finally, yes a compiler (perhaps in the hope of being a good debugging compiler) may change values which have become undefined. If the procedure references the n-th element of an array, it's allowed to assume that there are n-1 elements before it and set them as it chooses, for an intent(out) dummy, but not an intent(inout) dummy. (If you access A(n)then the compiler is allowed to assume that that element, and all from the declared lower bound, exist.)

francescalus
  • 30,576
  • 16
  • 61
  • 96
  • I think the question is about something different. The values that do get passed are not of any concern. The question is about the rest of the array. If I pass a 10-element array to a `dimension(*), intent(out)` argument, where the subroutine accesses just 5, what happens to those other 5? What if the arg is `dimension(5), intent(out)` and I pass a 10-element array? – Vladimir F Героям слава Apr 17 '21 at 12:08
  • @VladimirF That's indeed a possible case. What if `A` is defined as `dimension(10)`, then I pass `A(2)` to a subroutine which has `dimension(*), intent(out) :: foo`, and only does `foo(3) = 0`? `foo(3)` is `A(4)`, which becomes zero. Would a compiler be allowed to change the values of `A(2:3)`? By which magic could `A(5:10)` become undefined? – Jellby Apr 17 '21 at 12:15
  • @Jellby, the actual argument and the dummy argument both become undefined on entry to the procedure. If in this example you define only `A(4)` but not `A(2)`, `A(3)`, `A(5)`, etc., then those other values remain undefined once the procedure has completed. If you can explain a little more why that isn't clear to you, I'll try to address in the answer. (And yes, `A(1)` remains defined, because that's not part of the actual argument.) – francescalus Apr 17 '21 at 12:22
  • @VladimirF, if the actual argument is 10 elements, then those ten elements all become undefined on entry to the procedure when associated with an `intent(out)` dummy argument. Why would you expect that only those parts of the actual argument which are "accessed" in some way are subject to undefinition? (Association with an explicit-shape array is slightly different, of course.) – francescalus Apr 17 '21 at 12:24
  • @francescalus I wouldn't, but the question, as I read it, wss specifically about those elements. – Vladimir F Героям слава Apr 17 '21 at 12:39
  • @VladimirF, ok now I understand your comment. If it's related to a misunderstanding of what the actual argument is when there's an assumed-size dummy array then I can clarify. (I think the actual misconception is that the compiler is involved in "undefining" particular array elements in some way. If we establish "the compiler doesn't need to work out what values to make undefined" some of the difficulties may go away.) – francescalus Apr 17 '21 at 12:53
  • @francescalus Would it be different if I passed `A(2:4)` instead of `A(2)` (not `A(2:)`)? Or does having a `dimension(*), intent(out)` (note, not `dimension(:)`), mean that potentially the whole `A` can become undefined? In that case even something seemingly harmless like `A(:,i)` could be very dangerous. – Jellby Apr 17 '21 at 13:42
  • @Jellby, having `A(2)` as an actual argument for an assumed-size dummy is exactly like using `A(2:)` instead (and different from `A(2:4)`). But only that part of `A` which is the actual argument would be undefined. `A(2:)` won't touch `A(1)` and `A(:,i)` won't affect `A(:,i+1)`. – francescalus Apr 17 '21 at 13:48
  • OK, so I guess thinking that the actual argument becomes undefined "before" entering the subroutine makes it easier to accept. – Jellby Apr 17 '21 at 13:57