After reading the article Object-Oriented Programming in Fortran 2003
Part 3: Parameterized Derived Types by Mark Leair I took the code of @ivanpribec that defines a parameterized derived type (PDT) and defined an equivalent traditional derived type to understand the advantages of PDTs, which I may tweet about:
- With a PDT one can concisely declare a type with a fixed size.
- A PDT can be generic to various KINDs.
- The definition of the PDT spells out how the component dimensions relate to each other. For a DT one can write comments about dimensions, as shown, but such comments can be wrong.
- For a DT the reader must search for the subroutine that allocates the DT, and that subroutine must be kept consistent with the DT definition if a component is added.
- With a DT the user may allocate components directly and get them wrong, or deallocate or some components and not others. And with allocation on assignment, you cannot easily tell from looking at the code where component allocations are occurring, perhaps inadvertently. Thus PDTs are safer.
The disadvantages of PDTs are that they are not as well supported by all compilers and that fewer Fortranners are familiar with them.
module lu_mod implicit none integer, parameter :: sp = kind(1.0), dp = kind(1.0d0) ! parameterized derived type from Ivan Pribec ! https://bit.ly/3sWPCOT type :: lu_work(wp,n) integer, kind :: wp = dp integer, len :: n real(wp) :: a(n,n),b(n) integer :: ipiv(n) logical :: factorized = .false. end type lu_work ! traditional derived type (dt) -- KIND is hard-coded type :: lu_work_dt real(dp), allocatable :: a(:,:) ! (n,n) real(dp), allocatable :: b(:) ! (n) integer , allocatable :: ipiv(:) ! (n) logical :: factorized = .false. end type lu_work_dt contains pure elemental subroutine alloc(x,n) type(lu_work_dt), intent(out) :: x ! components of x deallocated since intent(out) integer , intent(in) :: n allocate (x%a(n,n),x%b(n),x%ipiv(n)) end subroutine alloc end module lu_mod program test_lu use lu_mod, only: lu_work, lu_work_dt, sp, alloc implicit none type(lu_work(n=5)) :: w ! fixed size type(lu_work(n=:)) , allocatable :: x type(lu_work(wp=sp,n=:)), allocatable :: y ! single precision type(lu_work_dt) :: z integer :: n n = 5 allocate (lu_work(n=n)::x) ! double precision by default allocate (lu_work(wp=sp,n=n)::y) ! single precision allocate (z%a(n,n),z%b(n),z%ipiv(n)) ! allocate dt ! better to allocate derived type in subroutine as below call alloc(z,n) ! check the shapes and kinds of allocated components print*,shape(x%a),shape(x%b),shape(x%ipiv) ! 5 5 5 5 print*,shape(z%a),shape(z%b),shape(z%ipiv) ! 5 5 5 5 print*,kind(x%a),kind(y%a),kind(z%a) ! 8 4 8 end program test_lu