2

I would like to assign a pointer in a derived type that is contained in the same derived type. The code below gives me the error below. What is going on here, and how can I solve this?

   24 |         zoos(i)%tigers(1) => zoos(i)%animals(1, 1)
      |        1
Error: Expected bounds specification for 'zoos' at (1)
module mo_zoo
    implicit none
    type zoo
        integer, dimension(:,:), pointer :: animals
        integer, dimension(:), pointer :: tigers
        integer, dimension(:), pointer :: ducks
    end type zoo
   
    save
        type(zoo), dimension(:), pointer :: zoos
end module mo_zoo

program test
    use mo_zoo
    implicit none
    integer :: n_zoos
    integer :: i

    n_zoos = 4
    allocate(zoos(n_zoos))

    do i = 1, n_zoos
        allocate(zoos(i)%animals(10, 2))
        zoos(i)%tigers(1) => zoos(i)%animals(1, 1)
        zoos(i)%ducks(1) => zoos(i)%animals(1, 2)
    end do
end program test
Chiel
  • 6,006
  • 2
  • 32
  • 57
  • possibly a duplicate? https://stackoverflow.com/questions/22197682/fortran-90-expected-bounds-specification-during-pointer-assignment – Scientist May 07 '21 at 07:24
  • I think my case is more complex, because the pointer is contained in an array of derived types. – Chiel May 07 '21 at 07:33
  • Well first rule of pointers in fortran: Don't use pointers. Allocatables are almost always superior - and certainly the two dimensional array has no reason shown here not to be allocatable, possibly with the target attribute depending on what else you do – Ian Bush May 07 '21 at 07:35
  • But I'm struggling to understand the dimensionality of your arrays. Why is animals a two dimensional array, and tigers and ducks one dimensional? When you do the pointer assignment you only point at a single element, so why the one dimensional arrays? – Ian Bush May 07 '21 at 07:37
  • I would like to point to a range in the array. Sorry, my Fortran is rusty, this is my first coding in a long time. – Chiel May 07 '21 at 07:39
  • @IanBush. I made allocatables, target is not allowed in a derived type so this does not work. – Chiel May 07 '21 at 07:40
  • @Chiel Hi Chiel, target is not used for derived type components, but the whole object must be target. – Vladimir F Героям слава May 07 '21 at 07:43
  • OK, got it, this is the confusion over pointer to array as opposed to array of pointers (Fortran doesn't directly implement the latter). There must be a duplicate somewhere - the one pointed to by @King touches on it but I am sure there is better somewhere – Ian Bush May 07 '21 at 07:44
  • @VladimirF. But how does that work? What if I want the variable in the type to be target rather than the type itself? – Chiel May 07 '21 at 07:44
  • @Chiel That would actually make little sense. The compiler needs some guarantees about the object. – Vladimir F Героям слава May 07 '21 at 07:58

1 Answers1

5

The problem is nothing to do with the derived type, and the error message is wrong.

The problem is that zoos(i)%ducks is a pointer to an array, not an array of pointers, so you need to point zoos(i)%ducks at zoos(i)%animals(:, 2), rather than zoos(i)%ducks(1) at zoos(i)%animals(1, 2).

I have previously talked about this in this answer.

I believe this does what you want:

module mo_zoo
    implicit none
    type zoo
        integer, dimension(:,:), pointer :: animals
        integer, dimension(:), pointer :: tigers
        integer, dimension(:), pointer :: ducks
    end type zoo
   
    save
        type(zoo), dimension(:), pointer :: zoos
end module mo_zoo

program test
    use mo_zoo
    implicit none
    integer :: n_zoos
    integer :: i

    n_zoos = 4
    allocate(zoos(n_zoos))

    do i = 1, n_zoos
        allocate(zoos(i)%animals(10, 2))
        zoos(i)%tigers => zoos(i)%animals(:, 1)
        zoos(i)%ducks => zoos(i)%animals(:, 2)
    end do
end program test

I would also like to offer a frame challenge. As noted in the comments, particularly by Ian Bush, pointers in Fortran are notoriously error-prone.

I would recommend replacing any allocated pointers with allocatables. These allocatables also need to be targets if they have pointers pointing at them, like so:

module mo_zoo
    implicit none
    type zoo
        integer, dimension(:,:), allocatable :: animals
        integer, dimension(:), pointer :: tigers
        integer, dimension(:), pointer :: ducks
    end type zoo
   
    save
        type(zoo), dimension(:), allocatable, target :: zoos
end module mo_zoo

program test
    use mo_zoo
    implicit none
    integer :: n_zoos
    integer :: i

    n_zoos = 4
    allocate(zoos(n_zoos))

    do i = 1, n_zoos
        allocate(zoos(i)%animals(10, 2))
        zoos(i)%tigers => zoos(i)%animals(:, 1)
        zoos(i)%ducks => zoos(i)%animals(:, 2)
    end do
end program test

There are a number of advantages to using allocatables over pointers where possible:

  • The memory held by allocatables will automatically be freed when the allocatables drop out of scope1.
  • Compilers can make stronger assumptions about allocatables than about pointers, sometimes leading to faster code.

1 At least, this is true according to the Fortran standard. There are several outstanding problems with some compilers (notably this bug) relating to finalisation.

veryreverie
  • 2,871
  • 2
  • 13
  • 26
  • 1
    Indeed this worked. I thought that pointing to the first element would work, but I was obviously thinking to much C-style. – Chiel May 07 '21 at 08:03
  • @IanBush I agree completely. I'm just assuming that this is a mwe for something more complicated where pointers are necessary. – veryreverie May 07 '21 at 10:03
  • Understood - it's just the sight of the word pointer in a Fortran program makes me twitchy, especially when it looks like the programmer is coming from some sort of C background – Ian Bush May 07 '21 at 10:23
  • @veryreverie, gfortran is open source, so *you* have the luxury to download the code, fix any bugs you find, and submit a patch to gcc.gnu.org. Given that the number of gfortran volunteers has dwindled to 2 semi-active people, I'm sure your contributions will be welcomed. – steve May 07 '21 at 20:27
  • @steve True. If I had more time I'd certainly consider it. And I didn't mean to be rude to gfortran, it just felt wrong to promote allocatables based on a feature that hasn't been entirely implemented yet. – veryreverie May 08 '21 at 07:14
  • @veryreverie @ianbush I am not allowed to make animals an `allocatable, target` because this is not permitted in derived types. I'd prefer `allocatable` too, but I do not see how in this example. – Chiel May 08 '21 at 07:19
  • @Chiel Allocatable has been allowed in derived types since 2003 - in fact before that if you include the technical report – Ian Bush May 08 '21 at 07:34
  • @IanBush, but as far as I have tested it `allocatable, target` is not and that is what i need. I opened another question: https://stackoverflow.com/questions/67445077/assign-pointer-to-non-target-variables-in-a-function – Chiel May 08 '21 at 07:44
  • @chiel Look at the code provided in the second half of this answer. The variable zoo has the target. Not the component of the derived type. And yes, my original comment was misleading, but the answer provides exactly what you want to do as I understand it. That said the associate way mentioned in the answer to the new question is a more Fortran way to do it. – Ian Bush May 08 '21 at 08:53
  • @veryeverie, I don't understand what you mean. `allocatable` was added to the Fortran standard a long time before finalization. Are you saying gfortran should state that it does not support `allocatable` because of a few bugs with finalization? When finalization was added to gfortran, the volunteer who implemented it, added a number of test cases to the testsuite. He obviously missed a few cases. I would like formally apologize on behalf of the gfortran volunteers for the pathetic nature of gfortran conformance to the Fortran standard. – steve May 08 '21 at 18:13
  • @steve I'm not trying to be rude to gfortran, and I'm certainly not trying to be rude to the gfortran developers. I actually think gfortran is the best fortran compiler available, and it's the only one I use. I just feel bad advising the OP to use allocatables in a derived type without warning them that there are currently compiler bugs associated with doing exactly that, in the compiler they are using. If you think my answer should be different, by all means suggest an edit. – veryreverie May 08 '21 at 22:29
  • 1
    @veryreverie I've been also using Gfortran for my main compiler (thanks!!), and my experience is `allocatable` arrays in derived types are now very mature/stable, and I meet essentially no problem recently (e.g. even for "deep copy" of objects with nested allocatables). But I still avoid using (1) `final` routines (and intent(out) for objects), and (2) polymorphic assignment + auto-allocation of LHS (instead, I use sourced allocation like `allocate(objA, source=objB)`). With these two caveats in mind, I think `allocatable` are just "OK" to use (or recommend), particularly with gfort >= 10 :) – roygvib May 09 '21 at 04:59
  • 2
    (FWIW, not claiming about the answer, but I felt a bit over-worried(?) about allocatable components...) If possible, comparing the results with at least two compilers (ifort and gfort) might be useful as a suggestion (though I always forget to do so... XD) – roygvib May 09 '21 at 05:02
  • 1
    I use inten( out ) and polymorphic assignment + auto-allocation of LHS extensively with gfortran and have had no recent problems (gfortran 7+). I don't use finalisation (much) though - it's one of those features that always looks interesting to me but on examination doesn't quite fit my needs. – Ian Bush May 10 '21 at 08:31
  • 1
    @roygvib It's variations on [this bug](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90068) that I keep running into. – veryreverie May 10 '21 at 08:45