ena
ena

Reputation: 85

Segfault passing argument in Fortran

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

Answers (1)

francescalus
francescalus

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

Related Questions