Reputation: 85
I'm having trouble with fortran when passing parameters to a method.
For the context, I'm trying to learn how to implement object-oriented programmation in order to maintain a program written in Fortran 90.
I've written an example which shows what I'm trying to do, and I don't really know what's the good way to code it, and my researches on the web remain vain.
module animal_mod
type, abstract :: animal
integer :: age
contains
procedure(speak_interface), deferred :: speak
end type animal
abstract interface
subroutine speak_interface(self)
import :: animal
class(animal), intent(in) :: self
end subroutine
end interface
end module
module cat_mod
use animal_mod
type, extends (animal) :: cat
character (len=8) :: fur
contains
procedure :: speak => speak_cat
end type cat
contains
subroutine speak_cat(self)
class(cat), intent(in) :: self
print *, "Meow"
end subroutine
end module
program animals
use cat_mod
implicit none
type(cat) :: my_cat
my_cat%fur="Shiny"
my_cat%age=3
call make_it_speak(my_cat)
end program animals
subroutine make_it_speak(my_animal)
use animal_mod
class(animal), intent(in) :: my_animal
call my_animal%speak()
end subroutine
The problem is that i declare my variable as a type(cat), and my subroutine takes a class(animal) as a parameter. However, I can't declare a type(animal) because of the abstraction.
Could you help me about this topic?
PS: I've defined an interface because it was mentioned in the tutorials and the documentations I went through, but I didn't really get its point.
Upvotes: 2
Views: 171
Reputation: 32366
You have two questions: about the segmentation fault and about the interface.
To answer about the segmentation fault, the subroutine make_it_speak
has a polymorphic argument my_animal
. It is polymorphic because it is declared as class(animal)
. This requires that the main program - which calls this subroutine - must have an explicit interface available to it. Placing the subroutine into animal_mod
does that through use association. You can find much discussion in other questions and answers.
Coming to the abstract interface in animal_mod
, let's look at that module in isolation.
When declaring the deferred type-bound procedure speak
of the abstract type animal
its interface must be specified. Again, this interface must be an explicit interface for the type. The interface block is one way to provide this explicit interface. Another would be to have a procedure, perhaps called speak_animal
. With this latter, though, you're no longer really deferring.
Why can't you use speak_cat
, being one suitable implementation, as the interface rather than repeat yourself with speak_interface
? One major reason is that inside the module animal_mod
speak_cat
isn't visible. It isn't possible to make it available through use association as there would then be a cyclic dependency.
How about merging animal_mod
and cat_mod
to get this visibility? That won't work either: the passed argument of speak_cat
is of class(cat)
rather than the required class(animal)
. You need this to ensure that your class(dog)
s are happy.
So, your abstract interface block is the way to go.
Upvotes: 1