Now that you see where we’re going, let’s take a few steps back and start simple and slow. The following snippet demonstrates the syntax to define a new derived type:
type :: Person ❶
character(len=20) :: name ❷
... ❸
end type Person ❹
❷ Declares a component variable
❸ We can have as many of these as we want.
❹ Closes the type definition block
The type definition block always opens with type :: <type-name> and closes with end type <type-name>, akin to program/end program, function/end function, and others. All the component declarations go inside the type definition block, and you can have as many as you want. Components aren’t limited to built-in numeric, character, or logical types. You can include components that are instances of derived types, and, in some special cases, even those of the same type. Specifically, having derived types with pointers to components of the same type is a popular pattern used to build a linked list.
Like with all other variable declarations we’ve covered so far, you must place a derived type definition within the declarative section of the code; that is, before the executable section.
Tip Define a new derived type in a dedicated module, in a dedicated source file. It will keep you organized and will help maintain a mental map of where different types are defined. For example, if I want to define a Field derived type, I’ll define it and all its methods in a mod_field module, and store it in a mod_field.f 90 file. In some cases, it makes sense to define closely related derived types in the same module. There are no hard rules here–do what makes the most sense to you, and be consistent. No matter what your convention is, it’s good to have one.
How about a derived type to represent a physical quantity, such as water height or velocity? We could define this type simply as Field:
type :: Field ❶
character(len=:), allocatable :: name ❷
integer :: dims(2) ❸
end type Field ❹
❶ Begins Field type definition
❷ Field name; for example, “water_height” or “velocity”
❸ Domain dimensions in x and y
For now, our Field type can be as simple as just the name and an integer array of two elements that will contain the size of the domain for this field. In the previous version of tsunami, we specified these dimensions as im and jm, so the dims component will correspond to [im, jm]:
integer(int32), parameter :: im = 101, jm = 101 ❶
Definition In math or physics, a field represents an assignment of values of some quantity (such as water height or velocity) to points in space.
We’re now getting more comfortable with defining a new derived type. However, this is just a recipe for creating data structures. Let’s see how we can declare and initialize an instance of a brand new derived type.