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

Fortran Optional Arguments

Vasili_M_
Beginner
2,666 Views
I have a subroutine splits_str_to_int (s, delim, t1, t2, t3, t4, t5), where 
t2, t3, t4, and t5 are optional. I am creating a wrapper around it.

When using optional arguments in the wrapper subroutine, do I need to check
whether the arguments are present first?.

<code>Subroutine splits                    &
  (                                  &
    s, delim,                        &
    t1, t2, t3, t4, t5, t6, t7, t8,  & 
    pos                              &
  )

Character (len=*), Intent (in) :: s, delim
Character (len=*), Intent (in), Optional :: pos

Integer, Intent (out) :: t1
Integer, Intent (out), Optional :: t2, t3, t4, t5, t6, t7, t8

Integer :: nf

If (Present (t2)) Then    
  Call splits_str_to_int (s, delim, t1, t2)
Else If (Present (t3)) Then    
  Call splits_str_to_int (s, delim, t1, t2,t3)
Elre If (Present (t4)) Then    
  Call splits_str_to_int (s, delim, t1, t2, t3, t4)
Else If (Present (t5)) Then    
  Call splits_str_to_int (s, delim, t1, t2, t3, t4, t5)
End If

</code>
0 Kudos
1 Solution
mecej4
Honored Contributor III
2,666 Views

To the extent that optional arguments that may or may not be present can be passed along as actual arguments to other routines, yes. However, there are certain rules regarding optional arguments that your code does not satisfy. You have to provide explicit interfaces, and use the keyword=value form when arguments cannot be associated by position in the argument list.

Try the following fixed-up version. In the last call to "splits", "pos=pos" could be replaced by just "pos".

Program Test
  implicit none
  integer s, delim,sn,pos,t1,t2,t3,t4,t5,t6,t7,t8,t9

  Call splits (s, delim, sn=sn)
  Call splits (s, delim, sn=sn, pos=pos)
  Call splits (s, delim, t1, t2)
  Call splits (s, delim, t1, t2, pos=pos)
  Call splits (s, delim, t1, t2, t3, t4, t5, t6, t7, t8, t9)
  Call splits (s, delim, t1, t2, t3, t4, t5, t6, t7, t8, t9, pos=pos)

CONTAINS

Subroutine splits  (s, delim, t1, t2, t3, t4, t5, t6, t7, t8, sn, pos)
   implicit none
   Integer, Optional :: t1, t2, t3, t4, t5, t6, t7, t8, sn, pos
   Integer :: s,delim

   Call splits_str_to_str (s, delim, t1, t2, t3, t4, t5, t6, t7, t8, pos=pos)

End Subroutine


Subroutine splits_str_to_str  (s, delim, s1, s2, s3, s4, s5, s6, s7, s8, sn, pos)

     implicit none
     Integer, Optional :: s1, s2, s3, s4, s5, s6, s7, s8, sn, pos
     integer :: s,delim
     write(*,*)' In Splits_str_to_str',present(s1),present(s2),present(s3), &
               present(s4),present(s5),present(s6),present(s7),present(s8), &
               present(sn),present(pos)

End Subroutine

End Program

 

View solution in original post

0 Kudos
7 Replies
mecej4
Honored Contributor III
2,666 Views

If you are confident that your subprogram code will reference optional arguments only if they are present, no, you need not check. If you have, say, three optional arguments and all three will be present if the first one is, it is sufficient to check only for the presence of the first. On the other hand, if you reference an optional argument that is not present, your program is almost sure to crash.

If you can organize your code such that the number of instances of IF(PRESENT())THEN...ENDIF are few, yet sufficient to ensure that no optional argument is referenced if not present, you would have reached a good compromise.

0 Kudos
Vasili_M_
Beginner
2,666 Views

That means that I will be assuming some things, such as requirements of which optional arguments will be present?

0 Kudos
mecej4
Honored Contributor III
2,666 Views

Correct. Essentially, you make an agreement with yourself as to which groups of optional arguments will be present during various calls. If this is either inconvenient or hard to adhere to, you can use IF (PRESENT...), but avoid putting that inside DO loops.

0 Kudos
Vasili_M_
Beginner
2,666 Views
Would I be able to have the following code?

Program Test

  Call splits (s, delim, sn)
  Call splits (s, delim, sn, pos)
  Call splits (s, delim, t1, t2)
  Call splits (s, delim, t1, t2, pos)
  Call splits (s, delim, t1, t2, t3, t4, t5, t6, t7, t8, t9)
  Call splits (s, delim, t1, t2, t3, t4, t5, t6, t7, t8, t9, pos)

End Program


Subroutine splits  (s, delim, t1, t2, t3, t4, t5, t6, t7, t8, sn, pos)
   Integer, Optional :: s1, s2, s3, s4, s5, s6, s7, s8, sn, pos

   Call splits_str_to_str (s, delim, s1, s2, s3, s4, s5, s6, s7, s8, pos)

End Subroutine


Subroutine splits_str_to_str  (s, delim, s1, s2, s3, s4, s5, s6, s7, s8, sn, pos)

     Integer, Optional :: s1, s2, s3, s4, s5, s6, s7, s8, sn, pos

End Subroutine

 

0 Kudos
mecej4
Honored Contributor III
2,667 Views

To the extent that optional arguments that may or may not be present can be passed along as actual arguments to other routines, yes. However, there are certain rules regarding optional arguments that your code does not satisfy. You have to provide explicit interfaces, and use the keyword=value form when arguments cannot be associated by position in the argument list.

Try the following fixed-up version. In the last call to "splits", "pos=pos" could be replaced by just "pos".

Program Test
  implicit none
  integer s, delim,sn,pos,t1,t2,t3,t4,t5,t6,t7,t8,t9

  Call splits (s, delim, sn=sn)
  Call splits (s, delim, sn=sn, pos=pos)
  Call splits (s, delim, t1, t2)
  Call splits (s, delim, t1, t2, pos=pos)
  Call splits (s, delim, t1, t2, t3, t4, t5, t6, t7, t8, t9)
  Call splits (s, delim, t1, t2, t3, t4, t5, t6, t7, t8, t9, pos=pos)

CONTAINS

Subroutine splits  (s, delim, t1, t2, t3, t4, t5, t6, t7, t8, sn, pos)
   implicit none
   Integer, Optional :: t1, t2, t3, t4, t5, t6, t7, t8, sn, pos
   Integer :: s,delim

   Call splits_str_to_str (s, delim, t1, t2, t3, t4, t5, t6, t7, t8, pos=pos)

End Subroutine


Subroutine splits_str_to_str  (s, delim, s1, s2, s3, s4, s5, s6, s7, s8, sn, pos)

     implicit none
     Integer, Optional :: s1, s2, s3, s4, s5, s6, s7, s8, sn, pos
     integer :: s,delim
     write(*,*)' In Splits_str_to_str',present(s1),present(s2),present(s3), &
               present(s4),present(s5),present(s6),present(s7),present(s8), &
               present(sn),present(pos)

End Subroutine

End Program

 

0 Kudos
John_Campbell
New Contributor II
2,666 Views

You should review your original logic as it presents some problems.
The second and subsequent if tests are only possible if t2 is NOT present, which implies that all your subsequent calls, which include t2 will fail.

If (Present (t2)) Then
  Call splits_str_to_int (s, delim, t1, t2)

Else If (Present (t3)) Then   
  Call splits_str_to_int (s, delim, t1, t2,t3)     !  Present (t2) = .false.

An alternative may be to provide a sufficiently large vector for ti's and a count of how many ti's are returned.
Isn't this count a function of the content of "s", rather than the supplied t1, t2,...

John

0 Kudos
Vasili_M_
Beginner
2,666 Views

Yes you are right John

0 Kudos
Reply