(j3.2006) Conditional expressions

Van Snyder Van.Snyder
Tue Mar 15 22:10:55 EDT 2011


Here's a problem that I'd like to solve using a conditional expression.
None of the alternatives are as satisfactory.

  subroutine S ( A, B )
    real :: A(:)
    real, optional, target :: B(:)
    real,target :: C(merge(0,size(a),present(B)))
    real, pointer :: P(:)

    p => c
    if ( present(b) ) p => b

    call t ( a, p )
    ! a lot more code involving p

  end subroutine S

Taking the liberty to use the C syntax for a conditional expression, I'd
rather have

  subroutine S ( A, B )
    real :: A(:)
    real, optional :: B(:)
    real :: C(merge(0,size(a),present(B)))

    associate ( p => present(b) ? b : c )
      call t ( a, p )
      ! a lot more code involving p
    end associate

  end subroutine S

Notice there are no pointers or targets here.  The selector produces
either the object b or the object c, not one of the values, as MERGE
would.

The alternatives are

1. Have two versions of this routine, one with B and one without, glued
together with a generic name, with one using B and the other using C
(but called B, just not a dummy argument).  I'd put the execution part,
and matbe some of the specification part, in an include file to reduce
opportunities for divergence during maintenance.

2.  A macro would be a nicer solution, allowing to produce the body of
the associate construct twice, once with p=b and once with p=c,
selecting between the macro instantiations using present(b), but... we
axed macros at the last minute.

3.  Keep the pointer and targets, but strip off the pointer attribute
with an associate construct, hoping this helps optimizers and runtime
checkers:

    associate ( q => p )
      same stuff
    end associate

4.  Put the stuff that uses p (essentially the body of the associate
construct) in an internal subroutine and call it with either B or C as
its argument.

    if ( present(b) ) then
      call my_internal ( b )
    else
      call my_internal ( c )
    end if

This solution only works, of course, in the case that the place I want
to use it isn't already an internal subroutine.

5.  Like 4, but not an internal subroutine.  Would require more
arguments since host association wouldn't be available.

6.  Make B non-optional and require the caller always to provide it.

7.  Just live with pointers and targets.





More information about the J3 mailing list