1

With fortran, I am running in situations where I have multiple local variables whose size is derived from input parameters in a somewhat verbose manner, e.g.

program pbounds 
contains 
  subroutine sbounds(x) 
    integer,intent(in) :: x(:,:)
    integer y1(size(x,1)/3,size(x,2)/2)
    integer y2(size(x,1)/3,size(x,2)/2)
    integer y3(size(x,1)/3,size(x,2)/2)
    ! ... do some stuff 
  end subroutine sbounds
end program pbounds

This seems overly verbose as I keep repeating the size expression. Additionally, when a change is needed – e.g. when it turns out that I need a y4 and change size(x,1)/3 to size(x,1)/4 – for real-world code that doesn't look quite as neat, it is easy to miss one of the previous variables.

In my real code, other examples include declarations with sizes coming from verbose, repetitive composite type fields, such as

type(sometype), intent(in) :: obj
real :: arr1(obj%subfield%nmax, obj%subfield%nmax, obj%subfield%xmax, 3, 3)
real :: arr2(obj%subfield%nmax, obj%subfield%xmax)
...

Is it possible to define a name for the size expressions, without resorting to preprocessor macros or allocatable arrays?

The things I have tried

With allocatable variables, we can use a local variable as name for the size expressions, but we split the declaration of the local arrays over two lines each.

program pboundsx
contains
  subroutine sboundsx(x)
    integer,intent(in) :: x(:,:)
    integer,allocatable :: y1(:,:),y2(:,:),y3(:,:)
    integer s(2)
    s = [ size(x,1)/3, size(x,2)/2 ]
    allocate(y1(s(1),s(2)))
    allocate(y2(s(1),s(2)))
    allocate(y3(s(1),s(2)))
    ! ... do some stuff 
  end subroutine sboundsx
end program pboundsx

With preprocessor macros we can give the size expression a name, but at the cost of adding multiple preprocessor lines, that disturb the indentation pattern among other things.

program pboundsm
contains
  subroutine sboundsm(x)
    integer,intent(in) :: x(:,:)
#define s1 (size(x,1)/3)
#define s2 (size(x,2)/2)
    integer y1(s1,s2)
    integer y2(s1,s2)
    integer y3(s1,s2)
#undef s1
#undef s2
    ! ... do some stuff     
  end subroutine sboundsm
end program pboundsm

With a second subroutine we can make the sizes an explicit parameter, but this is probably the most verbose and obscure solution; even more so considering that in real-world code 'x' isn't the only parameter.

program pboundss
contains
  subroutine sboundss(x)
    integer, intent(in) :: x(:,:)
    call sboundss2(x,size(x,1)/3,size(x,2)/2)
  end subroutine sboundss
  subroutine sboundss2(x,s1,s2)
    integer, intent(in) :: x(:,:), s1, s2
    integer y1(s1,s2), y2(s1,s2), y3(s1,s2)
  end subroutine sboundss2
  ! ... do stuff
end program pboundss

If it was allowed to mix declarations and initialization, the solution would be simple – but it is not:

program pboundsv
contains
  subroutine sboundsv(x)
    integer,intent(in) :: x(:,:)
    integer s1 = size(x,1)/3, s2 = size(x,2)/3  ! INVALID DECLARATION
    integer y1(s1,s2), y2(s1,s2), y3(s1,s2)
    ! ... do stuff
  end subroutine sboundsv
end program pboundsv
6
  • 1
    Although not exactly an answer, could you consider integer, dimension(expr) :: y1, y2, ...? Commented Jan 28, 2017 at 11:01
  • Unfortunately, I haven't found a solution for this in my programs. Similar questions were asked here before but without any simple solution. Francescalus shows how at least limit the number of these expressions needed. Commented Jan 28, 2017 at 11:17
  • @francescalus Sadly it is almost only in the simplified example that all relevant variables have the same shape. It would have been a viable solution for one real case though, so thanks for the suggestion! Commented Jan 28, 2017 at 13:49
  • The question is tagged Fortran 90, but the example code requires at least Fortran 2003. Commented Jan 28, 2017 at 21:09
  • @IanH Can you clarify which part is 2003? I may want to avoid newer features to ensure wide compiler-compatibility. Commented Jan 29, 2017 at 17:01

2 Answers 2

4

If the compiler allows (*), it may be an option to include the subroutine body entirely into a block (= a new scope) and mix declarations and assignment:

program pboundsv
contains
    subroutine sboundsv(x)
        integer,intent(in) :: x(:,:)
        integer s1, s2
        s1 = size(x,1)/3 ; s2 = size(x,2)/3
        block
        integer y1(s1,s2), y2(s1,s2), y3(s1,s2)
        ! ... do stuff
        endblock
    endsubroutine
end program

(*) But, this is Fortran >95, and Oracle studio fortran 12.5 still cannot compile it (very sadly)... (gfortran and ifort seem OK).

Sign up to request clarification or add additional context in comments.

1 Comment

Pretty good solution! Sadly, with the project being supposed to "support a wide range of platforms" (i.e. compilers), I'm not sure I can use it. I will try to check.
1

A partial solution - while specification statements cannot depend on the value of a local variable(**), they can depend on previous specifications for other local variables. For example:

subroutine sbounds(x) 
  integer,intent(in) :: x(:,:)
  integer y1(size(x,1)/3,size(x,2)/2)
  integer y2(size(y1,1),size(y1,2))
  integer y3(size(y1,1),size(y1,2))
  ! ... do some stuff 
end subroutine sbounds

...

type(sometype), intent(in) :: obj
real :: arr1(obj%subfield%nmax, obj%subfield%nmax, obj%subfield%xmax, 3, 3)
real :: arr2(size(arr1,1), size(arr1,3))

In some cases this can make the logical structure of your declarations clearer - "the extent of this dimension of this variable is the same as the extent of this dimension of that variable", which might be a more relevant message to a reader of the code than the specific expression that calculates the extent.

** Note that it is various restrictions on specification and constant expressions that is the real issue with your last block of code. You can quite happily mix declarations with initializations and other declarations in Fortran (they are just specification statements), what you cannot do is mix specification statements with executable statements (block constructs and the like aside). Specification expressions cannot depend on the value of a local variable, in part because it otherwise becomes difficult to ensure a deterministic ordering, while constant expressions cannot depend on the value of any variable, because constant expressions are supposed to be constant (and able to be evaluated at compile time).

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.