Operator Overloading
Overview
Teaching: 10 min
Exercises: 5 minQuestions
What is operator overloading?
Objectives
Overload the ‘+’ operator.
Previously in the Interface Blocks episode, we saw how interfaces can be used to map one procedure name onto different underlying procedures based on the number, order, and type or arguments passed to the procedure. However, these interface blocks can be used with more than just procedures they can also be used for operators already defined in Fortran such as +
,-
, *
,/
,==
,/=
, and also operators such as .gt.
, .le.
etc.
Lets add a +
operator which appends one of our t_vector
objects to another creating a new t_vector
.
$ cp destructor.f90 operators.f90
$ nano operators.f90
module m_vector
implicit none
type t_vector
...
end type
interface t_vector
...
end interface
interface operator(+)
procedure:: add_vectors
end interface
type,extends(t_vector):: t_vector_3
...
end type
interface t_vector_3
procedure:: create_size_3_vector
end interface
contains
type(t_vector) function add_vectors(left,right)
implicit none
type(t_vector),intent(in):: left, right
integer:: i,total_size,result_i
total_size=left%num_elements+right%num_elements
add_vectors=create_sized_vector(total_size)
!copy over left vector elements
do i=1, left%num_elements
add_vectors%elements(i)=left%elements(i)
end do
!copy over right vector elements
result_i=left%num_elements+1
do i=1,right%num_elements
add_vectors%elements(result_i)=right%elements(i)
result_i=result_i+1
enddo
end function
subroutine destructor_vector(self)
...
end subroutine
subroutine destructor_vector_3(self)
...
end subroutine
subroutine display(vec)
...
end subroutine
type(t_vector) function create_empty_vector()
...
end function
type(t_vector) function create_sized_vector(vec_size)
...
end function
type(t_vector_3) function create_size_3_vector()
...
end function
end module
program main
use m_vector
implicit none
type(t_vector) numbers_some,numbers_less,numbers_all
numbers_some=t_vector(4)
numbers_some%elements(1)=1
numbers_some%elements(2)=2
numbers_some%elements(3)=3
numbers_some%elements(4)=4
print*, ""
print*, "numbers_some"
call numbers_some%display()
numbers_less=t_vector(2)
numbers_less%elements(1)=5
numbers_less%elements(2)=6
print*, ""
print*, "numbers_less"
call numbers_less%display()
numbers_all=numbers_some+numbers_less
print*, ""
print*, "numbers_all"
call numbers_all%display()
end program
In the main program you can see how the operator is used, exactly as if we were adding two numbers together, however in this case we are adding our two vectors together. Lets try it out.
$ gfortran operators.f90 -o operators
$ ./operators
numbers_some
t_vector:
num_elements= 4
elements=
1.00000000
2.00000000
3.00000000
4.00000000
numbers_less
t_vector:
num_elements= 2
elements=
5.00000000
6.00000000
numbers_all
t_vector:
num_elements= 6
elements=
1.00000000
2.00000000
3.00000000
4.00000000
5.00000000
6.00000000
Here you can see that the two vectors have been combined into numbers_all
with the left hand t_vector
object added first followed by the right hand t_vector
object added second. So the way we have implemented our operator(+)
the results are order dependent.
Which side of an operator?
Our main program above looks like so:
111 program main 112 use m_vector 113 implicit none 114 type(t_vector) numbers_some,numbers_less,numbers_all 115 type(t_vector_3) location 116 117 numbers_some=t_vector(4) 118 numbers_some%elements(1)=1 119 numbers_some%elements(2)=2 120 numbers_some%elements(3)=3 121 numbers_some%elements(4)=4 122 print*, "numbers_some" 123 call numbers_some%display() 124 125 numbers_less=t_vector(2) 126 numbers_less%elements(1)=5 127 numbers_less%elements(2)=6 128 print*, "numbers_less" 129 call numbers_less%display() 130 131 numbers_all=numbers_some+numbers_less 132 print*, "numbers_all" 133 call numbers_all%display() 134 135 end program
Line 131 is
numbers_all=numbers_some+numbers_less
what would line 133,call numbers_all%display()
print out if line 131 wherenumbers_all=numbers_less+numbers_some
instead?
t_vector: num_elements= 6 elements= 1.00000000 2.00000000 3.00000000 4.00000000 5.00000000 6.00000000
the same as before, the
+
operator is commutative, in other words the order doesn’t matter.t_vector: num_elements= 6 elements= 5.00000000 6.00000000 1.00000000 2.00000000 3.00000000 4.00000000
the contents of
numbers_less
has been added to the new vector first followed by the contents ofnumbers_some
.Solution
NO: while it is true that for the mathematical
+
operator the order doesn’t matter this is not true for in general for operators. The implementation of the operator must be written in a way that it is order independent and that is now how we wrote it in this case.YES: In our case the order does matter as we first copy the data in the object left side, passed first as
left
, then the object on the right, passed second asright
to the function.
Key Points
Common Fortran operators can be overloaded to work with your custom derived types.