Sam Harrison
Sam Harrison

Reputation: 123

Pointing to a object's type variable - Fortran

As I understand, a user-derived type's definition can't contain target attributes. E.g., this isn't allowed:

type TestType
    integer, target :: t
end type

However, it's fine for them to be a pointer:

type TestType2
    integer, pointer :: p
end type

My question is, then, how can one use a pointer to point at an object's type variable? For example, if I wanted an object of type(TestType2) to have its p variable point to an object of type(TestType)'s t variable, how would I go about this? For example:

type(TestType) :: tt
type(TestType2) :: tt2
tt%t = 1
tt%p => tt%t

Thanks!

Upvotes: 3

Views: 570

Answers (2)

Sam Harrison
Sam Harrison

Reputation: 123

Thanks @roygvib and @Vladimir F, I hadn't realised that giving the whole object variable the target attribute would allow me to point to any of its components. That worked perfectly.

For posterity, as my use case was a little more complex than the example above, I thought I'd post a more representative example of what I was trying to achieve. I was creating a grid system containing GridCells and Rivers, each GridCell having an array of Rivers, and each River also having an array of Rivers that flow into in (inflows) - these inflows would be Rivers that have been previously created and stored in the GridCell's array of rivers. I wanted to use pointers so that the inflows could just point to the corresponding river in a particular GridCell's rivers array.

The added complication is that River itself is an abstract type, extended by different SubRivers (SubRiver1 and SubRiver2 in the example below). I wanted the arrays of rivers and inflows to be of class(River) (i.e., polymorphic) and the only way to achieve that without Fortran complaining about polymorphic arrays was to create another user-derived type RiverElement with a polymorphic class(River), allocatable :: item property to store the river (see here).

Finally, because I couldn't set the inflows array such that each item was a pointer (setting inflows(:) as a pointer makes a pointer array, not an array of pointer), I had to create another user-derived type specifically for storing pointers to Rivers.

Here's the module with all the type definitions:

module TestModule
    implicit none

    type :: RiverPointer
        class(River), pointer :: item => null()
    end type

    type, abstract :: River
        type(RiverPointer), allocatable :: inflows(:)
        integer :: id
    end type

    type :: RiverElement
        class(River), allocatable :: item
    end type

    type :: GridCell
        type(RiverElement), allocatable :: rivers(:)
    end type

    type, extends(River) :: SubRiver1
    end type

    type, extends(River) :: SubRiver2
    end type

end module

And here's a test program showing that it works:

program main
    use TestModule
    implicit none

    type(GridCell), target :: gc
    type(SubRiver1) :: sr1
    type(SubRiver2) :: sr2
    type(SubRiver1) :: sr3

    sr1%id = 1
    sr2%id = 2
    sr3%id = 3
    allocate(gc%rivers(3))
    allocate(gc%rivers(1)%item, source=sr1)
    allocate(gc%rivers(2)%item, source=sr2)
    allocate(gc%rivers(3)%item, source=sr3)

    allocate(sr3%inflows(2))
    sr3%inflows(1)%item => gc%rivers(1)%item
    sr3%inflows(2)%item => gc%rivers(2)%item

    write(*,*) sr3%inflows(1)%item%id           ! 1
    write(*,*) sr3%inflows(2)%item%id           ! 2
    gc%rivers(1)%item%id = 100
    write(*,*) sr3%inflows(1)%item%id           ! 100
end program

Thanks all!

Upvotes: 0

There would be very little sense in

type TestType
    integer, target :: t
end type

because values of type(TestType) may easily come up in contexts where they cannot be a target of a pointer.

As @roygvib comments, you have to give the target attribute to the whole object variable:

type(TestType), target :: tt

then you can make pointers to any of its components.

I could imagine that one could allow giving the target attribute to allocatable structure components in the type declaration, but it is not allowed. Certainly that would not make good sense for regular components.

Upvotes: 3

Related Questions