Fortran function returns a reference that can be placed on the left side of the job
As the name suggests, I want to directly modify the data I am accessing with a pointer obtained from a function. Having a reference returned by a function appearing on lhs assignment (=) is not a problem in C ++, but the following minimal example of fortran errors:
module test_mod
implicit none
integer, target :: a=1, b=2, c=3 ! some member variables
contains
function get(i)
integer, pointer :: get
integer, intent(in) :: i
select case (i)
case (1)
get => a
case (2)
get => b
case (3)
get => c
end select
end function get
end module test_mod
program test
use test_mod
implicit none
integer, pointer :: i_p
!> prints out 1 2 3
print*, get(1), get(2), get(3)
!> this is what I want but I get the error
!> Error: 'get' at (1) is not a variable
get(2) = 5
!> this works but is not what I want
i_p => get(2)
i_p = 5
end program test
Is there a way to accomplish this behavior; maybe I am missing some attributes? I would like to bypass the entries of any setter routines such as
set(i,value)
as it should mimic the appearance of an array. In my application, member variables a,b,c
are actually arrays of different sizes
a = [a1, a2, a3]
b = [b1, b2]
c = [c1]
and I want the getter to get(i,j)
simulate a matrix of pointers
j = 1 2 3 i = 1: [[a1, a2, a3], i = 2: [b1, b2, XX], i = 3: [c1, XX, XX]]
wehre XX
will link to null()
.
Update: I am using gfortran (version 5.2.0) and the deployment machines will only have versions 4.6.x and up. Therefore the proposed fortran 2008 features are unfortunately not available to me. Is it possible to simulate the above behavior without having a compiler supporting it out of the box?
Update 2: So I ended up implementing the struct like this
type Vec_t
integer, allocatable, dimension(:) :: vec
end type Vec_t
type(Vec_t), allocatable, dimension(:), target :: data
which I initialize as follows (my triangular matrix application which I mention at the end)
allocate(data(max))
do i=1,max
allocate(data(i)%vec(i))
end do
and I access it via
print*, data(2)%vec(1)
data(2)%vec(1) = 5
which is not what I was but good enough for my application.
source to share
See what you want to do:
get(2)=5
and the error message
Error: 'get' at (1) is not a variable
It looks pretty overwhelming: you can't do what you want. Or maybe ...
get(2)
indeed, by Fortran 2003 rules, not a variable. In Fortran 2003, a variable is specified by rules R601 and R603, which are a list of designators.
The left side of the assignment should be a variable.
But look at Fortran 2008 and its variable definition. Now the variable is either one of the same notation (or related to coarrays or complex parts), but can also (C602 - R602) be a reference to a function that
must have the result of a data pointer.
This is summarized in the introduction to Fortran 2008, which details extensions from Fortran 2003 as
A pointer function reference can denote a variable in any variable definition context.
get(2)
is a function reference that has the result of a data pointer. get(2)
then may appear on the left side of an assignment statement according to Fortran 2008 rules.
Alas, this Fortran interpretation is not supported by widespread compilers: at the time of answering the Cray compiler.
This means that this answer really says that you have two options: change the compiler or wait for this feature to become more common. Since both of them are probably impractical, you probably need another answer that provides something more portable as a workaround.
I prefer to refer to that provided innoSPG, since although the latter is based on the first, a description of the relevant field "pointer function - pointer ref - a variable" a little clearer. It is, however, a more accessible document and a viable alternative.
source to share