In Fortran, is the PARAMETER attribute set at runtime or compilation time?
I was wondering if I can pass in the size the of the array at run time and have this set as PARAMETER.
Can this be done? If so, how? If not, why?
Yes, as repeatedly answered, a named constant (an object with the parameter attribute) must have its initial value "known at compile time". However, as you talk about the size of arrays I'll note something else.
When declaring the shape of an array there are many times when the bounds needn't be given by constant expressions (of which a simple named constant is one example). So, in the main program or a module
implicit none
...
integer, dimension(n) :: array ! Not allowed unless n is a named constant.
end program
the n must be a constant. In many other contexts, though, n need only be a specification expression.
implicit none
integer n
read(*,*) n
block
! n is valid specification expression in the block construct
integer, dimension(n) :: array1
call hello(n)
end block
contains
subroutine hello(n)
integer, intent(in) :: n ! Again, n is a specification expression.
integer, dimension(2*n) :: array2
end subroutine
end program
That is, array1 and array2 are explicit shape automatic objects. For many purposes one doesn't really need a named constant.
Beyond the array size, the following is certainly not allowed, though.
implicit none
integer n, m
read(*,*) n, m
block
! n and m are specifications expression in the block construct
integer(kind=m), dimension(n) :: array ! But the kind needs a constant expression.
...
end block
You need dynamic allocation if the size of your array is to be defined as runtime. All parameter (constants) must be defined as compiling time.
The value of a parameter is set at compile time.
A declaration such as
integer, parameter :: number_of_widgets = numwidge
requires that numwidge be known at compile time, indeed known before it is encountered on the rhs of the declaration.
Related
I'm trying to decide which one of these two options would be the best:
subroutine sqtrace( Msize, Matrix, Value )
integer, intent(in) :: Msize
real*8, intent(in) :: Matrix(Msize, Msize)
real*8, intent(out) :: Value
[instructions...]
end subroutine sqtrace
VS
subroutine sqtrace( Matrix, Value )
real*8, intent(in) :: Matrix(:,:)
real*8, intent(out) :: Value
if ( size(Matrix,1) /= size(Matrix,2) ) then
[error case instructions]
end if
[instructions...]
end subroutine sqtrace
I understand that when you compile with warnings, the first case should automatically check at compile time if calls to sqtrace comply with the size indicated. However, I don't know if the compiler can perform those checks when the given arguments are allocatable, for example (more so if such allocation depends on other things that are determined at runtime). The second one requires an explicit interface and has more code (the checks), but would seem to catch more errors.
Which are the advantages/disadvantages of using each and in which cases should one go with one over the other?
First, some terminology. Consider the dummy arguments declared as
real :: a(n) ! An explicit shape array
real :: b(:) ! An assumed shape array
real, allocatable :: c(:) ! A deferred shape array (allocatable)
real, pointer :: d(:) ! A deferred shape array (pointer)
real :: e(*) ! An assumed size array
real :: f(..) ! An assumed rank array/scalar
I won't answer in terms of which is better in a given situation, but will simply detail some of the important characteristics leaving choice, where there is one, to the programmer. Crudely (and incorrectly), many view explicit shape arrays as "Fortran 77" and assumed and deferred shape arrays as "Fortran 90+".
Assumed size and assumed rank arguments are beyond the scope of this question and answer.
Shape:
the shape of an explicit shape array follows its declaration;
the shape of an assumed shape array dummy argument is that of the actual argument;
the shape of a deferred shape dummy argument may be undefined, becoming defined in the procedure, or that of the actual argument.
Contiguousness:
an explicit shape array is simply contiguous;
an assumed shape array dummy argument's contiguousness relates to that of the associated actual argument;
a deferred shape dummy argument may be that of the actual argument, or depending on the procedure's execution.
Restrictions on actual argument:
an actual argument associated with an explicit shape array must have at least as many elements as the dummy argument;
an actual argument associated with an assumed shape array must not itself be assumed size;
an actual argument associated with an assumed or deferred shape array must be of the same rank as the dummy argument.
Interfaces in the calling scope:
if a dummy argument is of assumed or deferred shape, the referencing scope must have accessible an explicit interface for the procedure.
Consider real a(6). This may be an actual argument to the dummies
real b(3)
real c(2,3)
real d(:) ! With an explicit interface available
a(1::2) may be associated with b but as b is contiguous copy-in/copy-out will be involved. Copy-in/copy-out needn't be involved when associated with d, but it may be.
There are plenty of other aspects, but hopefully this is an initial high-level introduction.
Fortran allows parametrizing the size of elements of derived types. However, where fixed-size elements can have a default value assigned in the type declaration, there doesn't seem to be a way for parametrized entries:
PROGRAM main
IMPLICIT NONE
TYPE data1
INTEGER :: array(5) = 2 ! allowed
END type data1
TYPE data2(n)
INTEGER, LEN :: n
INTEGER :: array(n) = 2 ! incorrect: error #8737 with intel fortran 19,
END type data2 ! ignored by gfortran 8.2.1
END PROGRAM main
Assigning default values is convenient, as it allows avoiding repeating the initialization every time the type is used, but for parametric-sized fields it isn't allowed; Gfortran just ignores the default value silently, and Intel Fortran issues an error
error #8737: For a default initialized component every type parameter and array bound
must be a constant expression. [ARRAY]
Is there any syntax, that would allow defining a default value after all?
There can be no default initialization for such components.
As the Intel Fortran error message states, the array bounds for a component with an initialization expression must be constant expressions (this is constraint C762 of Fortran 2018). The length type parameter is not usable as a constant expression.
There is no other syntax to specify a default value for the component.
A kind type parameter can feature in a constant expression, so components with bounds given by a kind parameter of that type can have default initialization.
You can create a constructor that takes the length parameter to create the object
module datatypes
type data2(n)
integer, len :: n
integer :: array(n)
contains
procedure, pass :: data2_fill2
end type
interface data2
module procedure new_data2
end interface
contains
subroutine data2_fill2(this)
class(data2(*)) :: this
this%array = 2
end subroutine
function new_data2(n) result(r)
integer, intent(in) :: n
type(data2(n)) :: r
call r%data2_fill2()
end function
end module
program Main
use datatypes
type(data2(3)) :: mydata
mydata = data2(100)
print *, "Size of array ", size(mydata%array)
if( mydata%array(1) /= 2) then
print *, "Something went wrong"
end if
end program
You have found a bug in different compilers. Your code is standard conforming. Fleshing out the code a bit, the following should print '2 2 2'.
program main
implicit none
!
! F2018, 7.5.1, page 64: A derived type can be parameterized by one or
! more type parameters, each of which is defined to be either a kind
! or length type parameter and can have a default value.
!
! F2018, 7.5.3.1, page 69: A type parameter may be used as a primary in
! a specification expression (10.1.11) in the derived-type-def.
!
! 10.1.11 Specification expression (page 156)
! ...
! R1028 specification-expr is scalar-int-expr
!
! C1010 (R1028) The scalar-int-expr shall be a restricted expression.
!
! A restricted expression is an expression in which each operation is
! intrinsic or defined by a specification function and each primary is
! ...
! (13) a type parameter of the derived type being defined,
!
type data2(n)
integer, len :: n
integer :: array(n) = 2
end type data2
type(data2(n=3)) :: a
print *, a%array ! This should print 2 2 2
end program main
gfortran compiles the code, but prints '0 0 0', so
gfortran has a bug in applying the component initialization.
I'm trying to decide which one of these two options would be the best:
subroutine sqtrace( Msize, Matrix, Value )
integer, intent(in) :: Msize
real*8, intent(in) :: Matrix(Msize, Msize)
real*8, intent(out) :: Value
[instructions...]
end subroutine sqtrace
VS
subroutine sqtrace( Matrix, Value )
real*8, intent(in) :: Matrix(:,:)
real*8, intent(out) :: Value
if ( size(Matrix,1) /= size(Matrix,2) ) then
[error case instructions]
end if
[instructions...]
end subroutine sqtrace
I understand that when you compile with warnings, the first case should automatically check at compile time if calls to sqtrace comply with the size indicated. However, I don't know if the compiler can perform those checks when the given arguments are allocatable, for example (more so if such allocation depends on other things that are determined at runtime). The second one requires an explicit interface and has more code (the checks), but would seem to catch more errors.
Which are the advantages/disadvantages of using each and in which cases should one go with one over the other?
First, some terminology. Consider the dummy arguments declared as
real :: a(n) ! An explicit shape array
real :: b(:) ! An assumed shape array
real, allocatable :: c(:) ! A deferred shape array (allocatable)
real, pointer :: d(:) ! A deferred shape array (pointer)
real :: e(*) ! An assumed size array
real :: f(..) ! An assumed rank array/scalar
I won't answer in terms of which is better in a given situation, but will simply detail some of the important characteristics leaving choice, where there is one, to the programmer. Crudely (and incorrectly), many view explicit shape arrays as "Fortran 77" and assumed and deferred shape arrays as "Fortran 90+".
Assumed size and assumed rank arguments are beyond the scope of this question and answer.
Shape:
the shape of an explicit shape array follows its declaration;
the shape of an assumed shape array dummy argument is that of the actual argument;
the shape of a deferred shape dummy argument may be undefined, becoming defined in the procedure, or that of the actual argument.
Contiguousness:
an explicit shape array is simply contiguous;
an assumed shape array dummy argument's contiguousness relates to that of the associated actual argument;
a deferred shape dummy argument may be that of the actual argument, or depending on the procedure's execution.
Restrictions on actual argument:
an actual argument associated with an explicit shape array must have at least as many elements as the dummy argument;
an actual argument associated with an assumed shape array must not itself be assumed size;
an actual argument associated with an assumed or deferred shape array must be of the same rank as the dummy argument.
Interfaces in the calling scope:
if a dummy argument is of assumed or deferred shape, the referencing scope must have accessible an explicit interface for the procedure.
Consider real a(6). This may be an actual argument to the dummies
real b(3)
real c(2,3)
real d(:) ! With an explicit interface available
a(1::2) may be associated with b but as b is contiguous copy-in/copy-out will be involved. Copy-in/copy-out needn't be involved when associated with d, but it may be.
There are plenty of other aspects, but hopefully this is an initial high-level introduction.
In Fortran, is the PARAMETER attribute set at runtime or compilation time?
I was wondering if I can pass in the size the of the array at run time and have this set as PARAMETER.
Can this be done? If so, how? If not, why?
Yes, as repeatedly answered, a named constant (an object with the parameter attribute) must have its initial value "known at compile time". However, as you talk about the size of arrays I'll note something else.
When declaring the shape of an array there are many times when the bounds needn't be given by constant expressions (of which a simple named constant is one example). So, in the main program or a module
implicit none
...
integer, dimension(n) :: array ! Not allowed unless n is a named constant.
end program
the n must be a constant. In many other contexts, though, n need only be a specification expression.
implicit none
integer n
read(*,*) n
block
! n is valid specification expression in the block construct
integer, dimension(n) :: array1
call hello(n)
end block
contains
subroutine hello(n)
integer, intent(in) :: n ! Again, n is a specification expression.
integer, dimension(2*n) :: array2
end subroutine
end program
That is, array1 and array2 are explicit shape automatic objects. For many purposes one doesn't really need a named constant.
Beyond the array size, the following is certainly not allowed, though.
implicit none
integer n, m
read(*,*) n, m
block
! n and m are specifications expression in the block construct
integer(kind=m), dimension(n) :: array ! But the kind needs a constant expression.
...
end block
You need dynamic allocation if the size of your array is to be defined as runtime. All parameter (constants) must be defined as compiling time.
The value of a parameter is set at compile time.
A declaration such as
integer, parameter :: number_of_widgets = numwidge
requires that numwidge be known at compile time, indeed known before it is encountered on the rhs of the declaration.
Why is it that Fortran will promote a scalar expression to an array, in an expression, but not as an argument to a procedure? In particular, why did the standards body make this design decision? Is it solely because of ambiguity, should the procedure be overloaded? Could an error message in that situation be an alternative approach?
For example, In the code below, the last statement, x = foo(7), produces the GFortran error: Error: Rank mismatch in argument 'a' at (1) (1 and 0).
module m
public :: foo
contains
function foo(a) result(b)
integer, dimension(:) :: a
integer, dimension(size(a)) :: b
b = a+1
end function foo
end module m
program p
use m
integer, dimension(4) :: x
integer, parameter, dimension(4) :: y = (/1,2,3,4/)
x = 7
x = foo(x)
x = foo(y)
x = foo(x + 7)
x = foo(7)
end program p
This question should have asked about why an array assignment will promote a scalar value source to an array target; unlike an array function. I expect that's simply a convenient special case though. Any comments gratefully received in the begging caps below.
If you want the function to handle scaler and array arguments, declare it as "elemental" and with scaler dummy arguments. Then it will be able to handle both scaler and array actual arguments, including scaler expressions. Will that meet your need?
The change:
elemental function foo(a) result(b)
integer, intent (in) :: a
integer :: b
b = a+1
end function foo
Perhaps they provided a way to do what you want, and one way was enough?
Procedure calling in Fortran with explicit interfaces (which you get automatically when using module procedures) requires a TKR (type, kind, rank) match. As an array is a different type than a scalar, not to mention the rank mismatch, this is not allowed.
Is it because of ambiguity should the procedure be overloaded?
That would be a problem, yes.
Could an error message in that situation be an alternative approach?
Could pink unicorns exist? Maybe, but to the best of my knowledge they don't. IOW, the Fortran standard currently requires TKR matching, and thus a standard conforming compiler must enforce this requirement. If you want to change that, I recommend making a proposal to the standards committee.
I would think the answer to this is pretty clear. Let's slightly modify your example:
module m
public :: foo
contains
function foo(a) result(b)
integer, dimension(:) :: a
integer, dimension(size(a)) :: b
b = a+1
a(2) = -777 ! new line; modify one element
end function foo
end module m
program p
use m
integer :: x
integer, dimension(4) :: y
x = 7
y = foo(x) ! pass a scalar
end program p
what is x supposed to be after the call to foo?
Now, sure, you could have the semantics of argument passing change depending on whether or not it's an intent(in) variable, but that is not something which is going to clarify things for programmers.
If the function call is supposed to 'distribute' somehow over array elements, then as MSB points out, elemental is the way to go. Otherwise, one just makes sure one's arguments match one's parameters.