# The best practice to share data among different derived types?

**URL:** <https://fortran-lang.discourse.group/t/the-best-practice-to-share-data-among-different-derived-types/8862>\
**Category:** Uncategorized\
**Created:** [November 21, 2024, 1:41am UTC](https://fortran-lang.discourse.group/t/the-best-practice-to-share-data-among-different-derived-types/8862 "2024-11-21T01:41:56Z")\
**Posts on this page:** 18\
**Page:** 1

<div class="post-metadata">

**Author:** ![jsjie](https://avatars.discourse-cdn.com/v4/letter/j/f17d59/32.png) [@jsjie](https://fortran-lang.discourse.group/u/jsjie)\
**Post date:** [November 21, 2024, 1:41am UTC](https://fortran-lang.discourse.group/t/the-best-practice-to-share-data-among-different-derived-types/8862/1 "2024-11-21T01:41:56Z")

</div>

This is a MWE for what I want to do:

```auto
module TestMod
    implicit none
    type, public :: SharedData
        integer, allocatable :: var(:)
    end type SharedData

    type, public :: F1
        type(SharedData), pointer :: share => null()
    end type F1

    type, public :: F2
        type(SharedData), pointer :: share => null()
    end type F2

    type, public ::TotalData
        type(SharedData) :: share
        type(F1) :: f1
        type(F2) :: f2
    end type TotalData
contains
    subroutine allocate_total(total)
        type(TotalData), intent(inout) :: total
        integer :: i
        allocate(total%share%var(10))
        do i = 1, 10
            total%share%var(i) = i + 1
        end do
        total%f1%share => total%share
        total%f2%share => total%share
        return
    end subroutine allocate_total

    subroutine deallocate_total(total)
        type(TotalData), intent(inout) :: total
        nullify(total%f1%share)
        nullify(total%f2%share)
        deallocate(total%share%var)
        return
    end subroutine deallocate_total
    
end module TestMod

program MyTest
    use TestMod
    implicit none
    type(TotalData) :: total
    integer :: i
    call allocate_total(total)
    do i = 1, 10
        print *, total%share%var(i)
    end do
    do i = 1, 10
        print *, total%f1%share%var(i)
    end do
    do i = 1, 10
        print *, total%f2%share%var(i)
    end do
    call deallocate_total(total)
    return
end program MyTest

```

Basically, I will need to do something within F1, something else within F2, and some others within TotalData. All will need SharedData, but as the name suggests, they all share one copy.  
In the real case, the SharedData is large, so I don’t want to copy it. Then I came to the idea to put the real data in TotalData, and access with pointers in F1 and F2. However, the above code will not compile, because

```auto
Error: Pointer assignment target is neither TARGET nor POINTER at (1)

```

for the lines

```auto
        total%f1%share => total%share
        total%f2%share => total%share

```

How can I fix the problem? Besides, do I really need to use pointers in this scenario? Are there better ways to do it?

---

<div class="post-metadata">

**Author:** ![gronki](https://avatars.discourse-cdn.com/v4/letter/g/a88e4f/32.png) [@gronki](https://fortran-lang.discourse.group/u/gronki)\
**Post date:** [November 21, 2024, 1:55am UTC](https://fortran-lang.discourse.group/t/the-best-practice-to-share-data-among-different-derived-types/8862/2 "2024-11-21T01:55:43Z")

</div>

> [@jsjie](#):
>
> ```auto
> type(TotalData), intent(inout) :: total
> 
> ```

I think this needs `target` attribute.

---

<div class="post-metadata">

**Author:** ![jsjie](https://avatars.discourse-cdn.com/v4/letter/j/f17d59/32.png) [@jsjie](https://fortran-lang.discourse.group/u/jsjie)\
**Post date:** [November 21, 2024, 2:00am UTC](https://fortran-lang.discourse.group/t/the-best-practice-to-share-data-among-different-derived-types/8862/3 "2024-11-21T02:00:52Z")

</div>

It works, thanks. Besides, how about the second question? Are there better ways to do it? I’m under the impression that many people only use pointers in Fortran for C interoperability, so I suppose pointers can be avoided in this case?

---

<div class="post-metadata">

**Author:** ![hkvzjal](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/hkvzjal/32/3055_2.png) [@hkvzjal](https://fortran-lang.discourse.group/u/hkvzjal)\
**Post date:** [November 21, 2024, 2:13am UTC](https://fortran-lang.discourse.group/t/the-best-practice-to-share-data-among-different-derived-types/8862/4 "2024-11-21T02:13:30Z")

</div>

Maybe this thread can be of interest to you

> [@Ownership for Fortran pointers](https://fortran-lang.discourse.group/t/ownership-for-fortran-pointers/8084):
>
> For quite a long time I’ve being thinking if there could be a way of making usage of pointer a bit safer in Fortran. They offer many advantages but can be tricky if one is not careful about memory management. I have found very useful to define DTs with pointer components which can actually hold the data or simply point to external data and encapsulate processing procedures around the given DT. In order to have the flexibility of using the same DT as owner or pointer of the data I’ve used the fo…

---

<div class="post-metadata">

**Author:** ![RonShepard](https://avatars.discourse-cdn.com/v4/letter/r/a3d4f5/32.png) [@RonShepard](https://fortran-lang.discourse.group/u/RonShepard)\
**Post date:** [November 21, 2024, 3:15am UTC](https://fortran-lang.discourse.group/t/the-best-practice-to-share-data-among-different-derived-types/8862/5 "2024-11-21T03:15:10Z")

</div>

> [@gronki](#):
>
> I think this needs `target` attribute.

Also, the declaration of `total` in the main program needs the target attribute. Otherwise, in principle, temporary copies can be used for the dummy argument association.

Another general approach that can be used is to define an allocatable component within `f1` and `f2`, and then right before `f1` is used, a `move_alloc()` is used to move the allocation into `f1`, and upon return it is moved back to the `total` derived type. This avoids the downsides of pointers, but it puts more burden on the programmer to do the shallow copies in the right order.

---

<div class="post-metadata">

**Author:** ![jsjie](https://avatars.discourse-cdn.com/v4/letter/j/f17d59/32.png) [@jsjie](https://fortran-lang.discourse.group/u/jsjie)\
**Post date:** [November 21, 2024, 4:05am UTC](https://fortran-lang.discourse.group/t/the-best-practice-to-share-data-among-different-derived-types/8862/6 "2024-11-21T04:05:03Z")

</div>

Can `move_alloc()` be used on derived types as a whole? I suppose it can only be used on arrays. In the real case, there will be many arrays in `SharedData`, and it will tedious if I have to manually `move_alloc()` all of them.

---

<div class="post-metadata">

**Author:** ![jwmwalrus](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/jwmwalrus/32/4483_2.png) [@jwmwalrus](https://fortran-lang.discourse.group/u/jwmwalrus)\
**Post date:** [November 21, 2024, 5:32am UTC](https://fortran-lang.discourse.group/t/the-best-practice-to-share-data-among-different-derived-types/8862/7 "2024-11-21T05:32:11Z")

</div>

> [@jsjie](#):
>
> I’m under the impression that many people only use pointers in Fortran for C interoperability, …

C and Fortran pointers are related, but not the same (e.g., you cannot do `p => t(2::2)` in C). Pointers need the `target` attribute, which may inhibit optimizations.

> [@jsjie](#):
>
> Are there better ways to do it?

“Better” depends on your actual use case. Maybe you can think of `TotalData` as an object that implements some algorithm, with its sub-algorithms needing some “wrapping”:

```fortran
module TestMod
    implicit none
    private

    type, public :: SharedData
        integer, allocatable :: var(:)
    end type SharedData

    type, public :: F1
        integer :: f1_data = 1
    contains
        procedure :: do_thing => do_f1_thing
    end type F1

    type, public :: F2
        integer :: f2_data = 2
    contains
        procedure :: do_thing => do_f2_thing
    end type F2

    type, public ::TotalData
        private
        type(SharedData) :: share
        type(F1) :: f1
        type(F2) :: f2
    contains
        private
        procedure, public :: run_algorithm
        procedure :: do_f1_thing => do_f1_thing_with_shared
        procedure :: do_f2_thing => do_f2_thing_with_shared
    end type TotalData

    public allocate_total
    public deallocate_total
contains
    subroutine allocate_total(total)
        type(TotalData), intent(inout) :: total
        integer :: i
        allocate(total%share%var(10))
        do i = 1, 10
            total%share%var(i) = i + 1
            print '("share(",i0,") = ",g0)', i, total%share%var(i)
        end do
    end subroutine allocate_total

    subroutine deallocate_total(total)
        type(TotalData), intent(out) :: total
        ! deallocate(total%share%var)
    end subroutine deallocate_total

    subroutine do_f1_thing(this, share)
        class(F1), intent(inout) :: this
        type(SharedData), intent(in) :: share
        print *, 'F1 sum = ', sum(this%f1_data * share%var)
    end subroutine

    subroutine do_f2_thing(this, share)
        class(F2), intent(inout) :: this
        type(SharedData), intent(in) :: share
        print *, 'F2 sum = ', sum(this%f2_data * share%var)
    end subroutine

    subroutine run_algorithm(this)
        class(TotalData), intent(inout) :: this
        call this%do_f1_thing()
        call this%do_f2_thing()
    end subroutine

    subroutine do_f1_thing_with_shared(this)
        class(TotalData), intent(inout) :: this
        call this%f1%do_thing(this%share)
    end subroutine

    subroutine do_f2_thing_with_shared(this)
        class(TotalData), intent(inout) :: this
        call this%f2%do_thing(this%share)
    end subroutine
end module TestMod

program MyTest
    use TestMod
    implicit none
    type(TotalData) :: total
    integer :: i
    call allocate_total(total)
    call total%run_algorithm()
    call deallocate_total(total)
end program MyTest

```

---

<div class="post-metadata">

**Author:** ![RonShepard](https://avatars.discourse-cdn.com/v4/letter/r/a3d4f5/32.png) [@RonShepard](https://fortran-lang.discourse.group/u/RonShepard)\
**Post date:** [November 21, 2024, 6:16am UTC](https://fortran-lang.discourse.group/t/the-best-practice-to-share-data-among-different-derived-types/8862/8 "2024-11-21T06:16:26Z")

</div>

> [@jsjie](#):
>
> Can `move_alloc()` be used on derived types as a whole?

Yes, any type including derived types, and scalars or arrays.

---

<div class="post-metadata">

**Author:** ![gronki](https://avatars.discourse-cdn.com/v4/letter/g/a88e4f/32.png) [@gronki](https://fortran-lang.discourse.group/u/gronki)\
**Post date:** [November 21, 2024, 10:43am UTC](https://fortran-lang.discourse.group/t/the-best-practice-to-share-data-among-different-derived-types/8862/9 "2024-11-21T10:43:42Z")

</div>

Sorry but I went to sleep by then. Indeed pointers are mostly used to avoid copies. There is nothing particularly wrong with your design. Another option would be simply passing shared data as a dummy argument when your computational routine is called, but that could increase number of arguments very fast.

In Python it is a commonly seen pattern to add a reference to some particular data structure to avoid passing it every time when calling computations. Unfortunately, Fortran much more prefers single-ownership of data, and pointers are really only used when that would be non feasible.

---

<div class="post-metadata">

**Author:** ![jsjie](https://avatars.discourse-cdn.com/v4/letter/j/f17d59/32.png) [@jsjie](https://fortran-lang.discourse.group/u/jsjie)\
**Post date:** [November 22, 2024, 6:43am UTC](https://fortran-lang.discourse.group/t/the-best-practice-to-share-data-among-different-derived-types/8862/11 "2024-11-22T06:43:27Z")

</div>

From my observation, some Fortran projects mostly use modular variables to store data, instead of construct objects of derived types. The example will be somehow like

```auto
module SharedData
        implicit none
        integer, allocatable :: var(:)
end module TestMod

module F1Mod
        use SharedData, only : var
end module F1Mod

module F2Mod
        use SharedData, only : var
end module F2Mod

program MyTest
        use SharedData, only : var
        use F1Mod
        use F2Mod
        implicit none
        allocate(var(10))
        ! call F1Mod subroutines
        ! call F2Mod subroutines
        deallocate(var)
        return
end program MyTest

```

This approach can be rationalized by the fact that for heavy scientific computation problems, usually only one task will be run in one process. However, I feel that this approach is rarely used in other software programming languages, where the usage of global variables are usually discouraged?  
Anyway, in my opinion, performance is the most important for these use cases, and I’m curious about how much compilers will behave differently among these designs. I’m concerned about the claim of @jwmwalrus that “Pointers need the target attribute, which may inhibit optimizations”. Does this mean that the pointer version may be slower?

---

<div class="post-metadata">

**Author:** ![jwmwalrus](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/jwmwalrus/32/4483_2.png) [@jwmwalrus](https://fortran-lang.discourse.group/u/jwmwalrus)\
**Post date:** [November 22, 2024, 3:36pm UTC](https://fortran-lang.discourse.group/t/the-best-practice-to-share-data-among-different-derived-types/8862/12 "2024-11-22T15:36:39Z")

</div>

> [@jsjie](#):
>
> This approach can be rationalized by the fact that for heavy scientific computation problems, usually only one task will be run in one process. However, I feel that this approach is rarely used in other software programming languages, where the usage of global variables are usually discouraged?

One reason I can think of is concurrency and the avoidance of race conditions. E.g., C has re-entrant versions of some functions, thus avoiding static access.

Although it’s not just in other languages: In Fortran, the PURE prefix helps in making access to module variables read-only (in Fortran 2023, things went further with SIMPLE procedures, which isolate said procedure from the environment that CONTAINS it). And since Fortran 2018 made RECURSIVE the default behavior, the SAVE attribute/statement is out of the question.

In the case TARGET arguments possibly inhibiting certain optimizations, I was referring to the concept of [aliasing](https://en.wikipedia.org/wiki/Aliasing_(computing)). The TARGET attribute tells the compiler that there may be more than one way to access that variable.

Btw, C has a ‘restrict’ keyword that does the opposite —i.e., tells the compiler that, at the time of invocation, no other pointer is pointing to that same location.

---

<div class="post-metadata">

**Author:** ![gronki](https://avatars.discourse-cdn.com/v4/letter/g/a88e4f/32.png) [@gronki](https://fortran-lang.discourse.group/u/gronki)\
**Post date:** [November 24, 2024, 4:21pm UTC](https://fortran-lang.discourse.group/t/the-best-practice-to-share-data-among-different-derived-types/8862/13 "2024-11-24T16:21:39Z")

</div>

> [@jwmwalrus](#):
>
> In the case TARGET arguments possibly inhibiting certain optimizations, I was referring to the concept of [aliasing](https://en.wikipedia.org/wiki/Aliasing_(computing)). The TARGET attribute tells the compiler that there may be more than one way to access that variable.

I have always heard this argument about aliasing, and multiple times it was given a reason for multiple restrictions inhibiting free development using pointers (try using pointers with pure procedures – just impossible). But I have a question in my head:

Is there at least one demonstrable case, where `pure` (or any similar restrictions in Fortran) actually has accelerated anything? C++ which, on the other hand gives the developer full trust and responsibility in managing aliases and memory, and does not burden the user with throwing `target` attributes in random places in their code seems to produce equally performant executables. Maybe someone perhaps did some test and could observe some measurable difference?

---

<div class="post-metadata">

**Author:** ![Beliavsky](https://avatars.discourse-cdn.com/v4/letter/b/ba8739/32.png) [@Beliavsky](https://fortran-lang.discourse.group/u/Beliavsky)\
**Post date:** [November 24, 2024, 4:42pm UTC](https://fortran-lang.discourse.group/t/the-best-practice-to-share-data-among-different-derived-types/8862/14 "2024-11-24T16:42:06Z")

</div>

> [@gronki](#):
>
> Is there at least one demonstrable case, where `pure` (or any similar restrictions in Fortran) actually has accelerated anything?

I have wondered about this and whether declaring arguments `intent(in)` (a requirement for pure functions) ever improves speed. I think it can if it enables the procedure to be called within a `do concurrent` loop, for which this is some [evidence](https://arxiv.org/abs/2408.07843) of speedups compared to a do loop.

---

<div class="post-metadata">

**Author:** ![gronki](https://avatars.discourse-cdn.com/v4/letter/g/a88e4f/32.png) [@gronki](https://fortran-lang.discourse.group/u/gronki)\
**Post date:** [November 24, 2024, 4:50pm UTC](https://fortran-lang.discourse.group/t/the-best-practice-to-share-data-among-different-derived-types/8862/15 "2024-11-24T16:50:42Z")

</div>

Personally, I avoid do concurrent since it has always been slower to me than a nested classical `do`, at least in `gfortran`.

---

<div class="post-metadata">

**Author:** ![jwmwalrus](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/jwmwalrus/32/4483_2.png) [@jwmwalrus](https://fortran-lang.discourse.group/u/jwmwalrus)\
**Post date:** [November 24, 2024, 5:09pm UTC](https://fortran-lang.discourse.group/t/the-best-practice-to-share-data-among-different-derived-types/8862/16 "2024-11-24T17:09:18Z")

</div>

I’m not sure, but I think `do concurrent` is implemented as serial in `gfortran` —just like the `async I/O` is actually implemented as synchronous.

And the Intel compilers (`ifort`/`ifx`) seem to need the `-parallel` flag (or something implying that flag) for concurrency to be effective.

---

<div class="post-metadata">

**Author:** ![gronki](https://avatars.discourse-cdn.com/v4/letter/g/a88e4f/32.png) [@gronki](https://fortran-lang.discourse.group/u/gronki)\
**Post date:** [November 24, 2024, 5:11pm UTC](https://fortran-lang.discourse.group/t/the-best-practice-to-share-data-among-different-derived-types/8862/17 "2024-11-24T17:11:10Z")

</div>

I was more targeting SIMD intrinsic being generated, but in the end I ended up manually writing all `do` loops. Maybe these days the implementations in the compilers at least not make things worse, but I never used `do concurrent` again.

---

<div class="post-metadata">

**Author:** ![cmaapic](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/cmaapic/32/659_2.png) [@cmaapic](https://fortran-lang.discourse.group/u/cmaapic)\
**Post date:** [November 25, 2024, 4:30pm UTC](https://fortran-lang.discourse.group/t/the-best-practice-to-share-data-among-different-derived-types/8862/18 "2024-11-25T16:30:12Z")

</div>

Jane and I did some simple benchmarking comparing whole array, simple do loop, do concurrent and openmp. Here are some timing figures.

| ch3305.f90 | Comparison of whole array, do loop, do concurrent and openmp | | | | | | | |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| | | | | | | | | |
| | Memory | | 128 GB | | | | | |
| | CPU | | Intel I9-10980XE | | | | | |
| | Cores | | 36 | | | | | |
| | | | | | | | | |
| | Nag | Intel | Intel | gfortran | gfortran | nvfortran | | |
| | windows | windows | linux | linux | windows | linux | | |
| | | ifort | ifort | | | | | |
| | | | | | | | | |
| | 7.1-7110 | 2021.10.0 | 2021.9.0 | 13.2.1 | 13.2.0 | 23.9-0 | | |
| | | | | | | | | |
| Whole array | 0.378274 | 0.196800 | 0.169849 | 0.191275 | 0.179287 | 0.170696 | | |
| Do loop | 0.185623 | 0.177500 | 0.180843 | 0.191207 | 0.179637 | 0.170382 | | |
| Do concurrent | 0.174196 | 0.039400 | 0.038133 | 0.178620 | 0.170870 | 0.170599 | | |
| openmp | 0.047436 | 0.042400 | 0.037865 | 0.045798 | 0.045414 | 0.045564 | | |
| | | | | | | | | |
| | Nag | Intel | Intel | gfortran | gfortran | nvfortran | Intel | Intel |
| | windows | windows | windows | linux | windows | linux | Linux | Linux |
| | | ifort | ifx | | | | ifort | ifx |
| | | | | | | | | |
| | 7.2-7211 | 2021.13.0 | 2024.2.0 | 14.2.1 | 13.2.0 | 23.9-0 | 2021.12.0 | 2024.1.0 |
| | | | | | | | | |
| Whole array | 0.390016 | 0.197000 | 0.222000 | 0.191406 | 0.189660 | 0.170696 | 0.161417 | 0.191566 |
| Do loop | 0.200121 | 0.181300 | 0.180843 | 0.190393 | 0.190490 | 0.170382 | 0.173227 | 0.171272 |
| Do concurrent | 0.175498 | 0.040500 | 0.173400 | 0.179210 | 0.177946 | 0.170599 | 0.038542 | 0.170461 |
| openmp | 0.047438 | 0.037700 | 0.044900 | 0.046552 | 0.046219 | 0.045564 | 0.038829 | 0.047107 |

Sadly intel ifort is no longer supported.

---

<div class="post-metadata">

**Author:** ![tyranids](https://avatars.discourse-cdn.com/v4/letter/t/3e96dc/32.png) [@tyranids](https://fortran-lang.discourse.group/u/tyranids)\
**Post date:** [November 25, 2024, 4:37pm UTC](https://fortran-lang.discourse.group/t/the-best-practice-to-share-data-among-different-derived-types/8862/19 "2024-11-25T16:37:17Z")

</div>

I have never observed any better binary generation for making procedures pure or marking arguments with intent in sadly.
