- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
What will be the best solution to affect default value to an optional argument?
subroutine dummy(logical_arg) logical,intent(in),optional :: logical_arg logical_value=.false. if( present(logical_arg)) logical_value=logical_arg .... if( logical_value) then ... endif .. end subroutine
or create a function get_arg_logical (and procedure get_arg_value for all kinds of arguments)
logical function get_arg_logical(default_value,logical_arg) logical,intent(in),optional :: logical_arg logical,intent(in) :: default_value get_arg_logical=default_value if( present(logical_arg)) get_arg_logical=logical_arg end function
and use get_arg_value(.false.,logical_arg) and so on where needed
subroutine dummy(logical_arg) logical,intent(in),optional :: logical_arg .... if( get_arg_value(.false.,logical_arg) ) then ... endif .. end subroutine
Thanks for your suggestions
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The second solution won't work: the "presentness" of an argument is not passed on to a subroutine.
An alternative to using optional arguments is the use of overloaded subroutines:
interface my_dummy
subroutine my_dummy_no_arg
subroutine my_dummy_with_arg
end interface my_dummy
subroutine my_dummy_no_arg
call my_dummy_with_arg( .false. )
end subroutine my_dummy_no_arg
subroutine my_dummy_with_arg
....
end subroutine my_dummy_with_arg
Of course just a sketch and it gets awkward with more than a few cases.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
arjenmarkus wrote:
the "presentness" of an argument is not passed on to a subroutine
If that were true, the usefulness of optional arguments would be substantially reduced.
However, the F2008 standard says in Section 12.5.2.12, Note 4: "Except as noted in the list above, it may be supplied as an actual argument corresponding to an optional dummy argument, which is then also considered not to be present" where "it" refers to an optional dummy argument that is not present. The restrictions are listed in Note 3 of the same section, and I do not see that any of them are violated in the example code.
Here is a complete test program to check this out.
program passoptl
call dummy(.true.)
call dummy(.false.)
call dummy()
contains
logical function get_arg_value(default_value,logical_arg)
implicit none
logical,intent(in),optional :: logical_arg
logical,intent(in) :: default_value
get_arg_value=default_value
if( present(logical_arg)) get_arg_value=logical_arg
end function get_arg_value
subroutine dummy(logical_arg)
implicit none
logical,intent(in),optional :: logical_arg
write(*,*)'Entered dummy()'
if( get_arg_value(.false.,logical_arg) ) then
write(*,*)'Branch false true'
else
write(*,*)'Branch false false'
endif
if( get_arg_value(.true.,logical_arg) ) then
write(*,*)'Branch true true'
else
write(*,*)'Branch true false'
endif
end subroutine dummy
end program passoptl
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Interesting, I was not aware of this.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I was not aware, either, and threads like this are valuable because they raise questions that make one read the standard carefully. The list of exceptions in Section 12.5.2.12, Note 3 is too long and the rules too complicated for me to remember, so I often fall back on asking myself if any quoted/misquoted rule would severely reduce the usefulness of the language. Such rules would have caused vendors and users to make strong objections to the standards committee, so a rereading of the relevant sections of the standard was indicated.
If passing along optional dummy arguments that are not present as actual arguments did not transmit the PRESENT status with the variables, it would have become necessary to have long chains of IF(PRESENT(...))THEN... blocks with all the possible combinations of the optional variables spelled out.
Reply to O.P.: I do not think that the overhead of using an additional function is justified, unless there are lots of instances of such assignments. The use of the literal constant .FALSE. as an actual argument in the second alternative makes the code less readable. If you modify the first alternative slightly as
IF( present(logical_arg)) THEN logical_value=logical_arg ELSE logical_value=.false. ENDIF
the code will be clearer. Let the compiler decide whether speculative assignment should be done.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks for your contributions.
In my mind, if an argument is not present, the value of it's pointer in the call stack is null. The PRESENT function only check if the pointer is null so it can be transmitted to inner calls.
That's why assigning a value to a non present argument crashes the app.
Is it right?
The solution with the function could make easier to search where default values are used.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Whether an optional argument that is not present is represented by a null pointer is an implementation detail that can change from compiler to compiler. Note that the processor need not even have a stack and still function perfectly well with compiled Fortran code. Another related question would relate to how to distinguish between optional arguments that are not present from pointer arguments that are present but are not yet associated.
If you wish to use the function alternative, it would be better to use a logical variable, say, "IsPresent", instead of the literal value .FALSE., for the sake of readability.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The pattern I tend to use for leaf procedures (procedures that aren't going to be passing the optional argument on to other procedures that also have a corresponding optional argument) is something like this:
SUBROUTINE sub_with_optional(..., arg)
LOGICAL, INTENT(IN), OPTIONAL :: arg
LOGICAL, PARAMETER :: default_arg = .FALSE. ! set accordingly
LOGICAL :: local_arg
IF (PRESENT(arg)) THEN
local_arg = arg
ELSE
local_arg = default_arg
END IF
some_variable = an_expression .involving. local_arg
CALL do_something_with(..., local_arg, etc)
END SUBROUTINE sub_with_optional
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page