Define a function/subroutine inside a derived type

Is there a way to define a function/subroutine inside a derived type? C++ has this feature.

class Box {
   public:
      double length;      
      double breadth;    
      double height;      
   
      double getVolume(void) {
         return length * breadth * height;
      }
};

Fortran has type-bound procedures, but the procedures are defined outside the definition of the type, as illustrated at the Fortran Wiki:

module class_Circle
  implicit none
  private
  real :: pi = 3.1415926535897931d0 ! Class-wide private constant
  type, public :: Circle
     real :: radius
   contains
     procedure :: area => circle_area
     procedure :: print => circle_print
  end type Circle
contains
  function circle_area(this) result(area)
    class(Circle), intent(in) :: this
    real :: area
    area = pi * this%radius**2
  end function circle_area

  subroutine circle_print(this)
    class(Circle), intent(in) :: this
    real :: area
    area = this%area()  ! Call the type-bound function
    print *, 'Circle: r = ', this%radius, ' area = ', area
  end subroutine circle_print
end module class_Circle
2 Likes

A function/subroutine defined outside of a derived type seems less integrated to the type than C++'s class member function. That’s why I ask this question. Not sure why it is designed like this.

PS: Why I must use the class keyword as opposed to type in the function/subroutine? Even when I do not plan to use extended types for the function/subroutine.

@fortran4r , please see this proposal at GitHub site for background on your question above:

1 Like

Fortran’s OOP feels really peculiar compared to C++…

Because C++ does not (did not) have modules? Before modules, all consumers of a C++ class had to #include more_source_code_to_parse_wasting_time.h.

Fortran has had modules since 1991 and the module information files (specific to each compiler) compile everything that a consumer needs to know in whatever quick-to-parse format the compiler writer prefers. The executable statements are not needed in the module information file. So the natural place for them is outside the type definition.

2 Likes

I understand what you said. But it still feels weird that a so-called type-bound procedure actually belongs to a module instead of a type.

module square_type
  public :: square, area

  type :: square
    real :: side
    
    contains
    procedure :: area  
  end type

  contains
  function area(x) 
    class(square) :: x
    real :: area
        
    area = x%side**2
  end function
end module

program main
  use square_type

  type(square) :: x
  real :: y, z

  x%side = 0.5

  y = x%area()
  
  z = area(x)
  
  print *, y == z

end program

It really isn’t that different to having a method implementation written outside of the C++ header file. E.g.,

// box.h
class Box {
   public:
      double length;      
      double breadth;    
      double height;      
   
      double getVolume(void);
};

// box.cxx
#include "box.h"
double Box::getVolume(void) {
         return length * breadth * height;
}

In Fortran we don’t talk about methods but about type-bound procedures. The idea is that an existing procedure gets bound to a derived type. This is why the first argument of a type-bound procedure is the instance of the derived type. This is closer to what is going on in the compiler really; method implementations don’t get written as part of the class data-structure, the class just has a means of looking up a function when the method is called.

I’m not sure of the exact arguments in the Standards Committee but I’m guessing the felt this was the smallest/simplest set of changes needed to the language to give OOP. Personally I find it quite a natural extension of Fortran 90.

4 Likes

Perhaps, but in C++ you can have the code divided over the header file and a source file.

Also, the way OO in Fortran works is that you can do:

call myobj%method

and:

call method( myobj )

plus control where the myobj argument is actually inserted in the argument list

It gives you the possibility to gradually go towards an OO interface or to allow for a procedural way of working :slight_smile: Endless flexibility is not always advantageous, but this definitely has its uses.

3 Likes

@fortran4r , see the excellent comments by @cmacmackin and @Arjen .

And also note Fortran also provides the following:

  1. It effectively unboxes the “hidden magic” with the “class” function parameter that is somehow always tied to a “method” in other OO languages such as C++. Many casual coders often fail to “get” this concept. Fortran effectively makes this concept explicit with the so-called “passed-object dummy argument”. To the OO cognoscenti this will be a rather silly thing but to the many scientists and engineers who are into domain expertise and not as much into programming paradigms and who tend to be inclined toward Fortran from their really simple days of working with FORTRAN, this is often a “light bulb” that goes off and they start to appreciate the more structured program organization which is what mainly is OO.
  2. Then with the PASS attribute, Fortran provides added flexibility in that the “passed-object dummy argument” i.e., the “class” on which the “method” operates can be positioned anywhere on the argument list i.e., it need not be the first dummy argument; first position is simply the default. This has its uses also.
  3. There is also NOPASS that readers can look up, this too has its uses.
3 Likes