[J3] Default values for optional arguments
Bill Long
longb at cray.com
Thu Jan 21 04:09:54 UTC 2021
> On Jan 20, 2021, at 9:14 PM, Kurt W Hirchert via J3 <j3 at mailman.j3-fortran.org> wrote:
>
> Not so brief historical flashback:
> During Fortran 8X development (i.e., development of what became Fortran 90), J3 considered argument defaulting, primarily as an alternative to explicitly optional arguments. Because of complaints that J3 was adding too much, they did not want to do both. Ultimately, J3 chose optional arguments, because defaulting could be implemented using optional arguments, but defaulting could not support everything that could be done with a general optional argument facility.
>
> During those discussions, J3 considered various paradigms for implementing default arguments using optional arguments. In addition to those already discussed in this thread, there was another you might consider:
>
> subroutine foo(a, b)
> integer, intent(in), optional :: b
> ...
> if (present(b)) then; call inner (b = b)
> else; call inner (b = 42); end if
> contains
> subroutine inner(b)
> integer :: b
> ! use a (via host association) and b (via argument association) to do whatever foo does
> end subroutine inner
> end subroutine foo
Can’t we already do this? If I remove the … line, the subroutine compiles just fine.
Cheers,
Bill
>
> This approach avoids the b vs. bval name confusion Thomas mentioned. It doesn't move the default into the procedure interface, but the body of foo essentially does little more than the defaulting, so it is still fairly visible. (If the processor can be convinced to expand foo in-line without expanding inner, you could get the effect of implementing defaulting in the caller.)
>
> You can't reference present(b) in inner, but most procedures are unlikely to need the value of present(b) once the value of b has been established. If you have one of the rare exceptions, you can add explicit code to capture the value of present(b) in foo and make it available in inner using another name (e.g., present_b).
>
> An advantage of using argument association rather than assignment is that it works for intent(out) and intent(inout) arguments as well as intent(in). Many library routines of that era had arguments that were nothing but workspace to be used by the routine. This approach could be used to create an interface that would work with existing programs but would allow the workspace argument(s) to be omitted in new programs. Optional return of intermediate computations could be implemented similarly. Optional dummy procedures are another possibility.
>
> One could use pointer association rather than argument association to avoid the extra calls, but pointer association often has more negative effects on optimization than argument association.
>
> If one needs to default a second argument c, the main logic of foo could be moved from inner to a second internal procedure inner2, and inner could become a defaulting "wrapper" similar to foo itself. In Fortran 90, inner2 could not be nested inside inner, so b would have to be explicitly passed to inner2 as well as c. This may be desirable even if you can nest inner2 inside inner, as there may be added cost to multi-level host association.
>
> A possible hybrid approach to defaulting multiple arguments might be to use assignment and pointer assignment to collect the defaulting in different names and then pass those different names to something like inner to get back to the original argument names.
>
> If you add conditional expression evaluation like the C ?: ternary operator to Fortran, the body of foo in the intent(in) case could be simplified to something like
>
> call inner(b = present(b) ? b : 42)
>
> greatly reducing its verbosity.
>
> --
>
> After writing the above, it occurs to me that we might be able to have much of the power of the above approach in a much simpler form. Imagine an assignment-like statement something like
>
> optional-dummy-argument ?=> argument
>
> with the semantics that if no actual argument is associated with that optional argument on the LHS, the RHS is evaluated/identified and becomes the actual argument associated with the dummy argument. This would reduce Thomas' example to
>
> b ?=> 42
>
> For the most common case, we might want to allow this ?=> operation to be specified on the declaration of an optional dummy argument, but having the stand-alone statement form allows more complex logic to be used in the determination of what actual argument to associate when such complexity is needed. (It would also allow the defaulting to be deferred until the value of present can be captured, in programs that need that.) [The existing rules that prevent an actual argument from "going away" while associated with a dummy argument might require some reinforcing to cover additional cases that could occur with this operation.]
>
> -Kurt
>
> P.S. To those who might have preferred that I put this on github, I apologize, but that is one new trick this old dog hasn't gotten around to learning.
>
> On 1/20/2021 1:32 AM, Thomas König via J3 wrote:
>>
>> A somewhat common thing to do for optional arguments is to set them
>> to a default value if the caller did not specify anything. One idiom
>> to do this would be
>>
>> subroutine foo(a, b)
>> integer, intent(in), optional :: b
>> integer :: b_val
>> ...
>> if (present(b)) then
>> b_val = b
>> else
>> b_val = 42
>> end if
>>
>> and then use b_val and c_val. This idiom is wasteful of lines (as
>> written, it takes five lines of code for a single default value). More
>> importantly, it is also error-prone because it is necessary to remember
>> to use b_val instead of b.
>>
>> The first drawback could be mitigated by doing something like
>>
>> if (present(b)) b_val = b
>> if (.not.present(b)) b_val = 42
>>
>> (not very clear, in my opinion) or by using yet-to-be-added conditional
>> expressions, but people would still have to use a different variable
>> name for essentially the same thing.
>>
>> What could help is to add some way to express default initialization for
>> optional arguments, something along the lines of
>>
>> integer, intent(in), optional :: b = 42
>>
>> or
>>
>> integer, intent(in), optional, default (42) :: b
>>
>> Opinions?
>>
>> Best regards
>>
>> Thomas
>
>
Bill Long longb at hpe.com
Engineer/Master , Fortran Technical Support & voice: 651-605-9024
Bioinformatics Software Development fax: 651-605-9143
Hewlett Packard Enterprise/ 2131 Lindau Lane/ Suite 1000/ Bloomington, MN 55425
More information about the J3
mailing list