I am learning oop in Fortran. And I wonder about the interest of overloading type bound procedure when the type of an argument is not known at compile time.
Let me explain, step by step my problem (These programs are only examples to increase my skill in fortran)
First program : overload of a type bound procedure
module my_mod
implicit none
type :: my_type_t
character(len=128) :: my_text
contains
procedure :: integer_print, real_print
generic :: my_print => integer_print, real_print
end type my_type_t
contains
subroutine integer_print(this, my_int)
class(my_type_t), intent(in) :: this
integer, intent(in) :: my_int
write (*,"(a,a,i0)") trim(this%my_text),' integer ', my_int
end subroutine integer_print
subroutine real_print(this, my_real)
class(my_type_t), intent(in) :: this
real, intent(in) :: my_real
write (*,"(a,a,f0.3)") trim(this%my_text),' real ', my_real
end subroutine real_print
end module my_mod
program my_pgm
use my_mod
implicit none
type(my_type_t) :: my_var
my_var%my_text = "Hello"
call my_var%my_print(10)
call my_var%my_print(9.9)
end program my_pgm
It gave the expected result. Either integer_print or real_print is used, depending of the type of my_print argument (integer or real).
Second program (or step, I should write) : an abstract type is used and there are two derived types : my_int_t and my_real_t. It is very similar to the first example. But, two types are used, one for integer and the other for real.
module my_mod
implicit none
type, abstract :: my_abstract_t
end type my_abstract_t
type, extends(my_abstract_t) :: my_int_t
integer :: an_integer
end type my_int_t
type, extends(my_abstract_t) :: my_real_t
real :: a_real
end type my_real_t
type :: my_type_t
character(len=128) :: my_text
contains
procedure :: integer_print, real_print
generic :: my_print => integer_print, real_print
end type my_type_t
contains
subroutine integer_print(this, my_int)
class(my_type_t), intent(in) :: this
type(my_int_t), intent(in) :: my_int
write (*,"(a,a,i0)") trim(this%my_text),' integer ', my_int%an_integer
end subroutine integer_print
subroutine real_print(this, my_real)
class(my_type_t), intent(in) :: this
type(my_real_t), intent(in) :: my_real
write (*,"(a,a,f0.3)") trim(this%my_text),' real ', my_real%a_real
end subroutine real_print
end module my_mod
program my_pgm
use my_mod
implicit none
type(my_type_t) :: my_var
type(my_int_t) :: my_int
type(my_real_t) :: my_real
my_var%my_text = "Hello"
my_int%an_integer = 10
my_real%a_real = 9.9
call my_var%my_print(my_int)
call my_var%my_print(my_real)
end program my_pgm
The type of my_int and my_real is known at compile type, so the output is correct. And the same call my_var%my_print(...) is used whatever the variable type (my_int_t or my_real_t), as in the first example.
But, now this is my problem.
program my_pgm
use my_mod
implicit none
type(my_type_t) :: my_var
class(my_abstract_t), allocatable :: my_number
allocate(my_int_t::my_number)
! or allocate(my_real_t::my_number)
my_var%my_text = "Hello"
select type (my_number)
type is (my_int_t)
my_number%an_integer = 10
type is (my_real_t)
my_number%a_real = 9.9
end select
select type (my_number)
type is (my_int_t)
call my_var%my_print(my_number)
type is (my_real_t)
call my_var%my_print(my_number)
end select
end program my_pgm
The type of my_number is not known at compile time. So, I must use a part of code that I found really redundant :
select type (my_number)
type is (my_int_t)
call my_var%my_print(my_number)
type is (my_real_t)
call my_var%my_print(my_number)
end select
I would have preferred to write only one line : call my_var%my_print(...) as in the first and second examples. Should I conclude that overloading of procedure have not interest in the third example and it is better to use integer_print and real_print directly in the select type block ? Or Is there something I haven't understood? ?
Edit 1
Following the comments of Francescalus, if I have well understood, I could not avoid the select type block. So, I modify the program in the following way.
module my_mod
implicit none
type, abstract :: my_abstract_t
end type my_abstract_t
type, extends(my_abstract_t) :: my_int_t
integer :: an_integer
end type my_int_t
type, extends(my_abstract_t) :: my_real_t
real :: a_real
end type my_real_t
type :: my_type_t
character(len=128) :: my_text
contains
procedure, private :: real_print, integer_print
procedure, public :: my_print
end type my_type_t
contains
subroutine integer_print(this, my_int)
class(my_type_t), intent(in) :: this
type(my_int_t), intent(in) :: my_int
write (*,"(a,a,i0)") trim(this%my_text),' integer ', my_int%an_integer
end subroutine integer_print
subroutine real_print(this, my_real)
class(my_type_t), intent(in) :: this
type(my_real_t), intent(in) :: my_real
write (*,"(a,a,f0.3)") trim(this%my_text),' real ', my_real%a_real
end subroutine real_print
subroutine my_print(this,my_number)
class(my_type_t), intent(in) :: this
class(my_abstract_t), intent(in) :: my_number
select type (my_number)
type is (my_int_t)
call this%integer_print(my_number)
type is (my_real_t)
call this%real_print(my_number)
end select
end subroutine my_print
end module my_mod
program my_pgm
use my_mod
implicit none
type(my_type_t) :: my_var
class(my_abstract_t), allocatable :: my_number1, my_number2
my_number1 = my_int_t(an_integer = 10)
my_number2 = my_real_t(a_real = 9.9)
my_var%my_text = "Hello"
call my_var%my_print(my_number1)
call my_var%my_print(my_number2)
end program my_pgm
Any comments would be appreciated.
my_number = my_int_t(10)ormy_number = my_real_t(9.9).