The_Learner
The_Learner

Reputation: 619

Fortran - Variable assignment and Declaration

I am trying to the assign value to a variable at the time of declaration and use that variable to declare the dimensions of some arrays as follows,

  type (typ_A), intent (in) :: str_A          
     
  integer, parameter :: 
x val_4 = (str_A%val_1 + str_A%val_2),
x val_5 = str_A%val_3

  integer :: array_1(str_A%val_1, str_A%val_2), array_2(val_4, val_5)

In this code, the array_1 is declared properly with the expected sizes but the array_2 is not declared. Also, I am getting errors like "This symbol must be a defined parameter, an enumerator, or an argument of an inquiry function that evaluates to a compile-time constant."

Note - I can straight away use the expression of val_4 to declare array_2, but sometimes, the expression (str_A%val_1 + str_A%val_2 + ....) is very large and have to use it to define multiple arrays. Hence, for better readability and less number of lines, I want to put it in a variable (val_4 in this case)

Upvotes: 4

Views: 1639

Answers (2)

mcocdawc
mcocdawc

Reputation: 1867

The answer of @dave_thompson_085 already answers the root for your problem.

A Fortran parameter must be computable at compile time

There are four possibilities to achieve the behaviour you want:

  1. If you use the block statement you create a local, nested scope where you can declare new variables. You can then declare arrays that use runtime variables outside of the block for their shapes.
integer :: n
n = compute_at_runtime()
block
    integer :: M(n)
    ! do something with M
end block
! M does not exist anymore
  1. As @dave_thompson_085 also put it in his answer, you can use contained procedures with a local nested scope, to declare array with runtime variables that exist outside of the procedure.

  2. Or you use allocatable for dynamic memory and automatic destruction/deallocation.

  3. Or you use pointer for dynamic memory, but then you have to manually cleanup.

Upvotes: 1

dave_thompson_085
dave_thompson_085

Reputation: 38821

A Fortran parameter must be computable at compile time, as the error message hints, and str_A%val_1 etc are not known at compile time. You can't use a variable directly for this, but you can create a nested argument:

subroutine x (str_A)
  type(whatever),intent(in)::str_A
  call x_2 (str_A, str_A%val_1 + str_A%val_2)
contains
  subroutine x_2 (str_A, mydim)
  type(whatever),intent(in)::str_A
  integer::mydim
  integer:: ary1(mydim), ary2(mydim), ary3(mydim)
  ...
  end subroutine x_2
end subroutine x

or if you can put at least the type and a helper function in a containing module you can do:

module t
  type whatever ...
contains
  pure function mydim(str_A)
    integer::mydim
    type(whatever),intent(in)::str_A
    mydim = str_A%val_1 + str_A%val_2
  end function mydim
  subroutine y (str_A)
    type(whatever),intent(in)::str_A
    integer:: ary1(mydim(str_A)), ary2(mydim(str_A)), ary3(mydim(str_A))
  ...
  end subroutine y
end module t

Added since you may not have considered/realized it:

Alternatively you could simply use ALLOCATABLE arrays instead; those can be allocated (not declared) with bounds computed by any runtime expression, including a local variable.

Upvotes: 4

Related Questions