# How implement a pointer to allocatable array inside a derived data type?

I have a mesh like so:

``````|  .  |   .   |   .   |  ...   |
0     1       2       3        nc
``````

To store the position of the cell boundaries, centers, etc., I have created the following derived data type:

testgrid1.f90 (2.1 KB)

``````   type :: grid
!! 1D grid
character(20) :: name = "x [-]"
!! variable name
real(rk), allocatable :: edges(:)
!! vector(0:nc) of cell edges
real(rk), allocatable :: center(:)
!! vector(nc) of cell centers, \( x_i \)
real(rk), allocatable :: width(:)
!! vector(nc) of cell widths,  \( x_{i+1/2} - x_{i-1/2} \)
real(rk), allocatable :: left(:)
!! vector(nc) of left cell boundaries, \( x_{i-1/2} \)
real(rk), allocatable :: right(:)
!! vector(nc) of right cell boundaries, , \( x_{i+1/2} \)
integer :: ncells
!! number of cells
contains
procedure, pass(self) :: new
end type grid
``````

This implementation works well and is convenient to use, but it is far from efficient in terms of memory, because the `left=edges(0:nc-1)` and `right=edges(1:nc)`. The same info is being stored 3 times.
To “solve” this problem, I naively thought about redefining `left` and `right` to be pointers that would point to `edges`, i.e, something like:

``````   type :: grid
!! 1D grid - DOES NOT WORK
character(20) :: name = "x [-]"
!! variable name
real(rk), allocatable, TARGET:: edges(:)
!! vector(0:nc) of cell edges
real(rk), allocatable :: center(:)
!! vector(nc) of cell centers, \( x_i \)
real(rk), allocatable :: width(:)
!! vector(nc) of cell widths,  \( x_{i+1/2} - x_{i-1/2} \)
real(rk), dimension(:), POINTER :: left
!! vector(nc) of left cell boundaries, \( x_{i-1/2} \)
real(rk), dimension(:), POINTER :: right
!! vector(nc) of right cell boundaries, , \( x_{i+1/2} \)
integer :: ncells
!! number of cells
contains
procedure, pass(self) :: new
end type grid
``````

But his kind of silly trick is completely illegal! The attribute `target` is not allowed inside a derived data type.
So, what is proper way to achieve the intended result?
Thanks!

You don’t need to declare a target inside your derived type, rather the instance of the derived type needs to have the target attribute

``````subroutine new(self)
class(grid), intent(out), target :: self
! ...
self%left => self%edges(0:self%ncells - 1)
self%right => self%edges(1:self%ncells)
end subroutine new
``````

Thanks once again, @awvwgk !
It seems extremely obvious, now that you explained it to me!

FWIW, I think you could just define an `elemental` type-bound function in your module for them:

``````elemental real(rk) function left(self,celli)
class(grid), intent(in) :: self
integer, intent(in) :: celli
left = self%edges(celli-1)
end function left
``````

This will be inlined by any compilers, and lets you avoid the pointer thing at all.

Is this really true? How can it (practically) be inlined when the procedure is only dispatched at runtime due to being type-bound?

Tried it at Compiler Explorer for comparison of the pointer and elemental implementation.

Attention @awvwgk , @HugoMVale ,

For a standard-conforming program, note it is not adequate for the parameter of the type-bound procedure to have the `TARGET` attribute, the passed object too must have the `TARGET` attribute in order for the associations to persist beyond the end of the procedure invocation.

For example, in your reproducer. the `gx` object in the `testgrid` main program shall be declared with a `TARGET` attribute.

Otherwise, the pointer associations such as `self%left => self%edges(..` only apply during the execution phase of the `new` procedure.

While technically true, I think the pointer will remain valid even outside the new procedure as the actual target is unlikely to move after leaving the procedure. To move the allocatable outside of new and keep the pointer valid the target attribute is required.

But sure, it can become an actual issue, therefore I try to avoid pointer components in derived types.

I’m not great at reading assembly, but in your example, it’s enough to turn on some non-zero level of optimization to achieve it: -O1 with ifort and -O2 with gfortran. Compiler experts will have better comments than mine, but I believe polymorphism only kicks in when you have a polymorphic variable (declared `class(whatever), allocatable`), while if your variable is statically typed (`type(whatever_1)`) the compiler knows exactly what functions have to be called, and can inline them

This may be true within the same file, but I don’t think you can make this statement more generally if this function could be called from a separately-compiled source file.
This is important because it could be the difference between a loop being vectorised or not.

Unless the compiler is storing implementation code in `.mod` files[1] (which I don’t think gfortran does) or you have specified link-time optimisation (lto), then the compiler has no way to inline the definition of a function or subroutine into a separately compiled file. This is one of the advantages of C++ in that included header files allow the compiler to see and inline the body of any functions that are declared and defined there.

By comparison, the simple pointer solution does not suffer from this limitation because accessing an element in the pointer array can be inlined and vectorised.

1. The mod files produced by `ifort` are often larger than those produced by gfortran, so I wondered whether they store code definitions to allow inlining, but I haven’t checked this. ↩︎

Right, mileage varies with compiler when it comes to link-time optimization. That’s also fully supported by gcc/gfortran afaict.

Going back to the problem, of course the `elemental` solution is not going to be super-fast if that function is used alot from outside the module; my guess is most of the finite-difference work will be done from within the module itself.

Your exact comment is one of the reasons I support the addition of the `inline` keyword for Fortran btw:
https://github.com/j3-fortran/fortran_proposals/issues/229