Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Array of extended objects in Fortran

Tags:

oop

fortran

UPDATE: Modified the code correcting the mistake, if anyone is interested in it as an example

I'm trying to get the hang of OOP in Fortran, but got some problems. Any help will be highly appreciated:

I want to store pointers to objects extended by an abstract class in an array and then call one of the abstract subroutines for these objects. However I get an compilation error where I'm trying to call the subroutine:

src/Body_set.f90(74): error #6553: A function reference is invoking a subroutine subprogram.   [GET_MASS]
        write(*,*) "Body ", i, " - mass: ", b%get_mass()
----------------------------------------------^
src/Body_set.f90(74): error #6402: prPromoteSym : Illegal KIND & CLASS mix   [GET_MASS]
        write(*,*) "Body ", i, " - mass: ", b%get_mass()
----------------------------------------------^
src/Body_set.f90(74): error #7021: Name invalid in this context   [GET_MASS]
        write(*,*) "Body ", i, " - mass: ", b%get_mass()
----------------------------------------------^
compilation aborted for src/Body_set.f90 (code 1)

I've got a abstract class in Body.f90 with two deferred procedures:

module Body_module
   implicit none
   private

   type, public, abstract :: Body
      private
   contains
      procedure(get_mass), deferred :: get_mass
      procedure(set_mass), deferred :: set_mass
   end type Body

   abstract interface
      function get_mass(self) result(m)
         import Body
         class(Body), intent(in)    :: self
         double precision m
      end function

      subroutine set_mass(self, m)
         import Body
         class(Body) :: self
         double precision m
      end subroutine
   end interface

end module Body_module

Then I've got a simple class with an pointer array that should keep different objects that extends the abstract Body class, Body_set.f90 (I've included all used subroutines, but the important one is at the bottom):

module Body_set_module
   use Body_module

   implicit none
   private

   type, public :: Body_container
      class(Body), pointer :: obj
   end type Body_container

   type, public :: Body_set
      private
      integer :: num_bodies
      type(Body_container), allocatable, dimension(:) :: bodies
   contains
      procedure :: set_body
      procedure :: get_body
      procedure :: get_num_bodies
      procedure :: print_summary
      final :: destructor
   end type Body_set

   interface Body_set
      procedure constructor
   end interface Body_set

contains

  !Object contructor
  function constructor(num_bodies) result(self)
     class(body_set),pointer :: self
     integer :: num_bodies

     allocate(self)
     self%num_bodies = num_bodies
     allocate(self%bodies(num_bodies))
  end function constructor

  !Returns number of bodies stored
  function get_num_bodies(self) result(num_bodies)
     class(Body_set), intent(in)  :: self
     integer                      :: num_bodies

     num_bodies = self%num_bodies
  end function get_num_bodies

  !Set element `i` to point to `new_body`
  subroutine set_body(self, new_body, i)
     class(body_set),    intent(inout) :: self
     class(Body), target, intent(in)    :: new_body
     integer,    intent(in) :: i

     self%bodies(i)%obj => new_body
  end subroutine set_body

   !Return pointer to body `i`
   function get_body(self, i) result(the_body)
     class(Body_set), intent(in)  :: self
     integer,         intent(in)  :: i
     class(Body),     pointer     :: the_body

     the_body => self%bodies(i)%obj
   end function get_body

Important part of Body_set.f90:

  !Print a summary of all bodies
  subroutine print_summary(self)
     class(body_set),  intent(in) :: self
     integer :: i
     class(Body),  pointer :: b

     write(*,*) "Summary of ", self%num_bodies, " bodies:"
     do i=1,self%get_num_bodies()
        b => self%get_body(i)
        write(*,*) "Body ", i, " - mass: ", b%get_mass()
     end do
  end subroutine print_summary


   subroutine destructor(self)
     type(body_set), intent(in) :: self
   end subroutine

end module Body_set_module
like image 541
Paul Avatar asked Sep 06 '13 09:09

Paul


People also ask

Is Fortran 90 object oriented?

C++ and Fortran 90 are compared as object-oriented languages for use in scientific computing. C++ is a full-featured, object-oriented language that provides support for inheritance and polymorphism.

What is a Fortran array?

It is a nonempty sequence of data and occupies a group of contiguous storage locations. An array has a name, a set of elements, and a type. An array name is a symbolic name for the whole sequence of data. An array element is one member of the sequence of data.

Can you do object oriented programming in Fortran?

Object Oriented Programming (OOP) is a programming method that represents concepts as “objects” that contain data and procedures which operate on the data. Objects offer an effective and structured way to organize computer programs. In fortran, modules are one important component of (OOP).

What is a class in Fortran?

Classes in Fortran are just plain type structures that contain attributes and methods. The functions and subroutines of a class have to be listed under contains . The visibility of each method can be set to either public or private .


1 Answers

The error is simple and very clear. You are calling a subroutine as a function. You can call a subroutine only using call. You probably wanted a function in the defining interface for get_mass.

like image 153
Vladimir F Героям слава Avatar answered Oct 09 '22 16:10

Vladimir F Героям слава