[J3] Default values for optional arguments

Kurt W Hirchert kurthirchert at gmail.com
Thu Jan 21 03:14:00 UTC 2021


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

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




More information about the J3 mailing list