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
```