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
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.
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.
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
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.
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 Endless flexibility is not always advantageous, but this definitely has its uses.
And also note Fortran also provides the following:
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.
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.
There is also NOPASS that readers can look up, this too has its uses.