Reputation: 1712
Currently in my code I have a 2D array
integer, allocatable :: elements(:,:)
and define some constants
integer, parameter :: TYP = 1
integer, parameter :: WIDTH = 2
integer, parameter :: HEIGHT = 3
! ...
integer, parameter :: NUM_ENTRIES = 10
and allocate something like
allocate(elements(NUM_ENTRIES,10000))
so I can access elements like
write(*,*) elements(WIDTH,100) ! gives the width of the 100th element
Now I would like to have not only integer but a mixture of types for every element. So I define a derived type
type Element
logical active
integer type
real width
! etc
end type
and use an array of Elements
type(Element), allocatable :: elements(:)
With the 2d array version I could call a subroutine telling it which entry to use. E.g.
subroutine find_average(entry, avg)
integer, intent(in) :: entry
real, intent(out) :: avg
integer i,
real s
s = 0
do i = lbound(elements,1), ubound(elements,1)
if (elements(TYP,i) .gt. 0) s = s + elements(entry,i)
end do
avg = s/(ubound(elements,1)-lbound(elements,1))
end subroutine
So I could call find_average(HEIGHT)
to find the average height or pass WIDTH
to get the average width.
(And my subroutines do more advanced things than finding the average height or width, this is just an example.)
Question: How can I use different types (as with the derived type) but also reuse my functions to work with different entries (as in the example subroutine)?
Upvotes: 3
Views: 6857
Reputation: 29391
For the array case, instead of passing in arguments array and index i, you could pass in the single argument array (i). When you switch to having the derived type, similarly you could pass in variable_of_type % element rather than passing in the entire variable_of_type and somehow instructing the procedure which subelement it is supposed to work on. If the code needs to be different for the different types of elements (e.g., logical, integer, real), then you could write specific procedures for each, but call then with a common name via a generic interface block. The compiler has to be able to distinguish the procedures of the generic interface block by some characteristic of the arguments, here their type. For a code example in which the distinguishing characteristic is array rank see how to write wrapper for 'allocate'
EDIT: example code. does this do what you want?
module my_subs
implicit none
interface my_sum
module procedure sum_real, sum_int
end interface my_sum
contains
subroutine sum_real (array, tot)
real, dimension(:), intent (in) :: array
real, intent (out) :: tot
integer :: i
tot = 1.0
do i=1, size (array)
tot = tot * array (i)
end do
end subroutine sum_real
subroutine sum_int (array, tot)
integer, dimension(:), intent (in) :: array
integer, intent (out) :: tot
integer :: i
tot = 0
do i=1, size (array)
tot = tot + array (i)
end do
end subroutine sum_int
end module my_subs
program test_dt
use my_subs
implicit none
type my_type
integer weight
real length
end type my_type
type (my_type), dimension (:), allocatable :: people
type (my_type) :: answer
allocate (people (2))
people (1) % weight = 1
people (1) % length = 1.0
people (2) % weight = 2
people (2) % length = 2.0
call my_sum ( people (:) % weight, answer % weight )
write (*, *) answer % weight
call my_sum ( people (:) % length, answer % length )
write (*, *) answer % length
end program test_dt
Upvotes: 4