Fortran

Guide To Learn

Implementing a custom subtraction operator

We have our datetime and timedelta classes. The question remains: How can we take the difference between two datetimes using nothing but an arithmetic subtraction operator? Doing just td = birthday - now won’t work out of the box because a datetime is an arbitrary data structure. To the compiler, it has no intrinsic meaning and is just a sequence of numbers in memory. If we try this, we won’t get far:

$ gfortran mod_datetime.f90 countdown.f90 -o countdown
countdown.f90:8:7:                                     ❶
 
   td = birthday - now                                 ❷
       1                                               ❸
Error: Unexpected derived-type entities in binary      ❹
       intrinsic numeric operator ‘-’ at (1)           ❹

❶ File name, line number, and column where the error occurred

❷ The code that triggered the error

❸ Approximate position where the error occurred

❹ Error message

We need to somehow tell the compiler that the operator - has a special meaning for these types, and instruct it on what to do when we try to use it in code. We can do so by associating an operator such as addition (+) or subtraction (-) with a user-defined procedure. Figure 10.1 illustrates the sequence of operations that occur when applying the custom subtraction operator (-) on two datetime instances, a and b.

Figure 10.1 Implementing arithmetic operators for derived types in three steps

We first invoke the subtraction operator with the two datetime instances. The compiler determines that a and b are not of built-in numeric types. It looks for any procedure that the - operator is associated with and that matches these data types, and finds datetime_minus_datetime. Under the hood, the compiler replaces the code a - b with datetime_minus_datetime(a, b). This function returns a timedelta instance as the result.

In the previous chapter, you learned how to override operators for built-in (nonderived) data types, as well as how to define your own custom operators. Now we get to see how to associate an operator with a derived type-bound procedure, as shown in the following listing.

Listing 10.4 Implementing the - operator for the datetime class

type :: datetime
  integer :: year, month, day
  integer :: hour = 0, minute = 0, second = 0
contains
  procedure, pass(d1) :: datetime_minus_datetime           ❶
  generic :: operator(-) => datetime_minus_datetime        ❷
end type datetime

❶ Type-bound procedure that will be invoked by the operator

❷ Operator “-” is now associated with this procedure.

There are two ingredients here. First, we specify the procedure that will associate the operator with a type-bound procedure, just like we did back in chapter 8. The keyword pass specifies the name of the argument that will correspond to the type instance that’s bound. For a refresher on type-bound methods, take a look at section 8.3. Second, we use the generic :: operator() => syntax to specify which operator will be replaced by which procedure. Defined like this, whenever the compiler encounters the - operator being applied to datetime instances, it will refer to the datetime_minus_datetime procedure.

Simple, right? Of course, we still need to write that datetime_minus_datetime procedure….

How about custom operators?

In chapter 9, I introduced the concept of custom operators enclosed in periods; for example, .sub.. The mechanism used in listing 10.4 isn’t restricted to built-in operators and can be used for custom operators as well; for example

generic :: operator(.sub.) => datetime_minus_datetime

would be a valid statement as well.

Implementing a custom subtraction operator

Leave a Reply

Your email address will not be published. Required fields are marked *

Scroll to top