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

User derived types argument with INTENT(OUT)

netphilou31
New Contributor II
721 Views

Hi,

I recently came to an issue which was not easy to find (even if the source code is quite small) with a derived type passed as argument and declared with the INTENT(OUT) statement in the called subroutine. I read the section of the help relating to the INTENT statement but without getting a clear answer.

Originally, there was a programming error from my side since the argument should have been declared INTENT(INOUT) since some its elements are used without being set before in the routine (they are defined in a parent subroutine) and some others are calculated in the routine.

My question is, why the compiler didn't warn me about the fact that I was using an element of a derived type before it was set (i.e. being on the right-hand side of an assignement expression but never found on the left-hand side of another one before) because of the INTENT(OUT) declaration?

For a simple scalar variable, the compiler would have given the following message:

warning #6843: A dummy argument with an explicit INTENT(OUT) declaration is not given an explicit value. [Var]

I agree that for complex UDTs with a lot of subitems, issuing a warning for all the items that are not set before the return may be a bit too much, but at least for those who are used would be nice, or in this particular case of INTENT(OUT), should I activate additional compiler diagnostics to get this message?

Best regards,

Phil.

0 Kudos
1 Solution
jimdempseyatthecove
Honored Contributor III
685 Views

The declaration of a UDT implicitly has a constructor, either implicit or explicit. Therefor the INTENT(OUT) is sufficient to construct the returned object.

Furthermore, there is no way to specify which UDT member: variables, arrays, allocatables pointers, or embedded UDT's are required to be set via =. 

IOW the implicit/explicit constructor is sufficient to define the returned object.

 

Jim Dempsey

View solution in original post

0 Kudos
4 Replies
andrew_4619
Honored Contributor II
704 Views

The intent serves two purposes it signals what the programmers design is meant to do, and it gives the compiler and opportunity to do some validation which is useful in flagging up many stupid code errors.  It is not always practical (or possible) for the compiler to check intent, for example any args passed on in a call to an external subprogram without an explicit interface is a total unknown.  The intent is therefore a safety guard but not an infallible one and I don't think the standards are prescriptive on this issue. 

jimdempseyatthecove
Honored Contributor III
686 Views

The declaration of a UDT implicitly has a constructor, either implicit or explicit. Therefor the INTENT(OUT) is sufficient to construct the returned object.

Furthermore, there is no way to specify which UDT member: variables, arrays, allocatables pointers, or embedded UDT's are required to be set via =. 

IOW the implicit/explicit constructor is sufficient to define the returned object.

 

Jim Dempsey

0 Kudos
FortranFan
Honored Contributor II
682 Views

@netphilou31 ,

Re: "why the compiler didn't warn me about the fact that I was using an element of a derived type before it was set," I will withhold any judgment on what it might take for a compiler to develop further user-friendly static code analysis and linting facilities.  It may take you forever if at all you manage to convince Intel Fortran team to add such a new feature to warn you in such situations.

In the meantime, something you can immediately consider to mitigate the problem you faced in future might be default initialization of your derived type components.  And to use `INTENT(OUT)` only when the use case for it is strong in a given code.  But let me guess based on prior posts, your response will be that you knew about all this already but you could not make use of it for legacy reasons x, y, and z, and so this threads of yours is only about the compiler but not your coding practices which then places you back in the scenario of the previous paragraph!  Thus the blurb below may be more for any other reader who may be open to using the facilities in the language.

 

module m
   type :: t
      integer :: n = 42 !<-- default initialization; applies to INTENT(OUT) cases also
   end type
contains
   subroutine sub( a )
      type(t), intent(out) :: a
      integer :: n
      print *, "In sub: a%n = ", a%n, "; expected is 42"
      n = a%n
      a%n = -99
   end subroutine 
end module
   use m
   type(t) :: u
   u%n = 1000
   call sub( u )
   print *, u%n, "; expected is -99"
end 
C:\temp>ifort /standard-semantics p.f90
Intel(R) Fortran Intel(R) 64 Compiler Classic for applications running on Intel(R) 64, Version 2021.7.0 Build 20220726_000000
Copyright (C) 1985-2022 Intel Corporation.  All rights reserved.

Microsoft (R) Incremental Linker Version 14.33.31630.0
Copyright (C) Microsoft Corporation.  All rights reserved.

-out:p.exe
-subsystem:console
p.obj

C:\temp>p.exe
 In sub: a%n =  42 ; expected is 42
 -99 ; expected is -99

 

0 Kudos
netphilou31
New Contributor II
422 Views

Hi,

Thanks for your answers.

I was not expecting the compiler to add an implicit constructor since the UDT is passed by reference, I assumed it was initialized when declared in the calling routine (with the default initialization I used, zero in my case), furthermore some of its components might be already intialized in a parent subroutine and only some others are modified in the called subroutine. That's what I thought (apparently incorrectly) the INTENT(OUT) was telling the compiler. The use of default initialization of the UDT components was the source of the problem because the other components were calculated elsewhere and then lost. I don't know if this is related but my wrong coding was working correctly for months (I was able to compare the results with another version of the code without the UDT arg, which was used to replace a COMMON bloc) and the behavior changed recently when I switched the floating-point option /fp:fast=2 to /fp:source.

Anyway, this was a good lesson about the need to correctly check the INTENT attributes of the dummy args, especially for UDTs! I spent some time to understand what was happening but fortunately a colleague was using another version (older) of the code, so we were able to run debug sessions in parallel and compare the calculated values.

Best regards,

Phil.

0 Kudos
Reply