Estou aprendendo POO em Fortran. E me pergunto sobre o interesse de sobrecarregar procedimentos com limite de tipo quando o tipo de um argumento não é conhecido em tempo de compilação.
Deixe-me explicar, passo a passo, meu problema (Esses programas são apenas exemplos para aumentar minha habilidade em fortran)
Primeiro programa: sobrecarga de um procedimento de tipo limitado
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
Deu o resultado esperado. Ou integer_print
ou real_print
é usado, dependendo do tipo de my_print
argumento (inteiro ou real).
Segundo programa (ou passo, eu diria): um tipo abstrato é usado e há dois tipos derivados: my_int_t
e my_real_t
. É muito semelhante ao primeiro exemplo. Mas, dois tipos são usados, um para inteiros e outro para reais.
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
O tipo de my_int
and my_real
é conhecido no momento da compilação, portanto a saída está correta. E a mesma chamada my_var%my_print(...)
é usada independentemente do tipo da variável ( my_int_t
or my_real_t
), como no primeiro exemplo.
Mas agora esse é o meu problema.
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
O tipo de my_number
não é conhecido em tempo de compilação. Então, preciso usar um trecho de código que achei bastante redundante:
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
Eu teria preferido escrever apenas uma linha: call my_var%my_print(...)
como no primeiro e no segundo exemplos. Devo concluir que a sobrecarga de procedimento não tem interesse no terceiro exemplo e é melhor usar integer_print
e real_print
diretamente no select type
bloco? Ou há algo que eu não entendi?
Edição 1
Seguindo os comentários de Francescalus, se entendi bem, não consegui evitar o select type
bloqueio. Então, modifiquei o programa da seguinte maneira.
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
Qualquer comentário será apreciado.
Pode-se usar despacho duplo , também chamado de padrão de visitante.
Esta é uma implementação de exemplo para o seu código. Ela tem a limitação óbvia de que o
my_type_t
tipo já precisa ser conhecido. No entanto, o uso deselect_type
é evitado e outros tipos de extensãomy_abstract_type
podem ser adicionados livremente.O ponto principal é fazer outro despacho quando
type(my_type_t)
já estiver disponível e mudar as implementações da impressão para os tipos individuais com os dados numéricos derivados dosmy_abstract_t
quais é preciso conhecer a estruturamy_type_t
- isso é uma desvantagem.