Modern Fortran OO Features
Salvatore Filippone
School of Aerospace, Transport and Manufacturing, [email protected]
IT4I, Ostrava, April 2016
S. Filippone (SATM) Modern Fortran OO Features IT4I, Ostrava, 2016 1 / 25 Preface
Premature optimization is the root of all evil — Donald Knuth Write 80% of your source code with yourself and your fellow programmers in mind, i.e. to make your life easier, not your computers life easier. The CPU will never read your source code without an interpreter or compiler anyway. Arcane or quirky constructs and names to impress upon the CPU the urgency or seriousness of your task might well get lost in the translation.
S. Filippone (SATM) Modern Fortran OO Features IT4I, Ostrava, 2016 2 / 25 Preface
Procedural programming is like an N-body problem — Lester Dye
“The overwhelming amount of time spent in maintenance and debugging is on finding bugs and taking the time to avoid unwanted side effects. The actual fix is relatively short!” – Shalloway & Trott, Design Patterns Explained, 2002.
S. Filippone (SATM) Modern Fortran OO Features IT4I, Ostrava, 2016 3 / 25 OOP – Recap
By widely held “received wisdom”, Object-Oriented Programming emphasizes the following features: 1 Encapsulation 2 Inheritance 3 Polymorphism All three are supported by Fortran.
S. Filippone (SATM) Modern Fortran OO Features IT4I, Ostrava, 2016 4 / 25 OOP nomenclature
Fortran C++ General Extensible derived type Class Abstract data type Component Data member Attribute class Base class pointer Dynamic Polymorphism Type guarding (select type) RTTI (dynamic cast) Type-bound procedure Virtual Member functions Method, operation* Parent type Base class Parent class Extended type Subclass Child class Module Namespace Package Generic interface Function overloading Static polymorphism Final Procedure Destructor Defined operator Overloaded operator Defined assignment Overloaded assignment Deferred procedure binding Pure virtual member function Abstract method Procedure interface Function prototype Procedure signature Intrinsic type/procedure Primitive type/procedure Built-in type procedure
S. Filippone (SATM) Modern Fortran OO Features IT4I, Ostrava, 2016 5 / 25 Encapsulation: Type-bound procedures
The first tenet of OOP is encapsulation: Package data, and bring the code (method) close to the data (object)
The Fortran concepts for this are derived types (which we have already seen) and type-bound procedures.
function greet(this) result(message) module astronaut_class class(astronaut), intent(in):: this implicit none character(len=max_string_length):: message private ! Hide everything by default message= this%greeting public:: astronaut ! Expose type & constructor end function integer,parameter:: max_string_length=100 end module type astronaut private program oo_hello_world character(len=max_string_length):: greeting use astronaut_class ,only : astronaut contains type(astronaut) :: pilot procedure:: greet ! Public by default pilot= astronaut(’Hello, world!’) end type print*, pilot%greet() contains end program
S. Filippone (SATM) Modern Fortran OO Features IT4I, Ostrava, 2016 6 / 25 Encapsulation: Type-bound procedures
Features of type-bound procedures: The name by which the procedure is invoked; The object on which it is invoked; The visibility; The extensibility (to be further explored later); Generic type-bound procedures
S. Filippone (SATM) Modern Fortran OO Features IT4I, Ostrava, 2016 7 / 25 Encapsulation: Type-bound procedures
contains module psb_base_mat_mod type:: psb_base_sparse_mat function psb_base_get_fmt() result(res) !> Row size implicit none integer(psb_ipk_), private::m character(len=5) :: res !> Col size res= ’NULL’ integer(psb_ipk_), private::n end function psb_base_get_fmt !> Matrix state: ! integer(psb_ipk_), private:: state integer(psb_ipk_), private:: duplicate function psb_base_get_nrows(a) result(res) logical, private:: triangle implicit none logical, private:: upper class(psb_base_sparse_mat), intent(in)::a logical, private:: unitd integer(psb_ipk_):: res logical, private:: sorted res= a%m logical, private:: repeatable_updates=.false. end function psb_base_get_nrows
contains function psb_base_get_ncols(a) result(res) implicit none procedure, pass(a):: get_nrows => psb_base_get_nrows class(psb_base_sparse_mat), intent(in)::a procedure, pass(a):: get_ncols => psb_base_get_ncols integer(psb_ipk_):: res procedure, nopass:: get_fmt => psb_base_get_fmt res= a%n end function psb_base_get_ncols end type psb_base_sparse_mat end module psb_base_mat_mod
S. Filippone (SATM) Modern Fortran OO Features IT4I, Ostrava, 2016 8 / 25 Encapsulation: Type-bound procedures
Type-bound procedures can be generic
type:: psb_base_sparse_mat ...... contains procedure, pass(a):: transp_1mat => psb_base_transp_1mat procedure, pass(a):: transp_2mat => psb_base_transp_2mat generic, public:: transp => transp_1mat, transp_2mat end type psb_base_sparse_mat
contains
subroutine psb_base_transp_1mat(a) class(psb_base_sparse_mat), intent(inout)::a integer(psb_ipk_):: itmp itmp= a%m a%m= a%n a%n= itmp a%triangle= a%triangle a%upper=.not.a%upper end subroutine psb_base_transp_1mat
subroutine psb_base_transp_2mat(a,b) class(psb_base_sparse_mat), intent(in)::a class(psb_base_sparse_mat), intent(out)::b b%m= a%n b%n= a%m b%triangle= a%triangle b%upper=.not.a%upper end subroutine psb_base_transp_2mat
S. Filippone (SATM) Modern Fortran OO Features IT4I, Ostrava, 2016 9 / 25 Inheritance: extending types
The second tenet of OOP is inheritance: Embrace and extend existing types
type:: speaker
contains procedure(talk) ,deferred:: speak end type
abstract interface function talk(this) result(message) import:: speaker,msg_max_length class(speaker) ,intent(in):: this !character(:) ,allocatable :: message character(len=msg_max_length):: message end function end interface S. Filippone (SATM) Modern Fortran OO Features IT4I, Ostrava, 2016 10 / 25 Inheritance: extending types
type,extends(speaker):: astronaut private character(len=msg_max_length):: greeting contains procedure:: speak => greet end type contains function greet(this) result(message) class(astronaut) ,intent(in):: this character(len=msg_max_length):: message message= this%greeting end function
S. Filippone (SATM) Modern Fortran OO Features IT4I, Ostrava, 2016 11 / 25 Inheritance: extending types
Rules: The extended type implicitly has all the comoponents of the parent type; The extended type implicitly has the parent type as a component; The extended type implicitly gets all of the methods of the parent type; You should only ever override specific procedures, generics work automatically
S. Filippone (SATM) Modern Fortran OO Features IT4I, Ostrava, 2016 12 / 25 Polymorphism: static and dynamic
The third tenet of OOP is polymorphism: Object instances may have different types Comes in two main varieties: Static polymorphism: the actual type can be resolved at compile time; Dynamic polymorphism: the actual type can only be resolved at runtime. Static polymorphism corresponds to the resolution of generic interfaces; we have already seen this in Fortran 95.
S. Filippone (SATM) Modern Fortran OO Features IT4I, Ostrava, 2016 13 / 25 Morpheus: Greek god of dreams
S. Filippone (SATM) Modern Fortran OO Features IT4I, Ostrava, 2016 14 / 25 Polymorphism
Dynamic polymorphism is signalled by the CLASS keyword; a polymorphic entity must be either A dummy argument; A variable with the ALLOCATABLE attribute; A variable with the POINTER attribute; Examples: type point real:: x,y end type point type(point):: vp class(point), pointer:: pp
pp => vp
S. Filippone (SATM) Modern Fortran OO Features IT4I, Ostrava, 2016 15 / 25 Polymorphism
A polymorphic variable may get its type by: The actual argument passed to a subroutine; The association between a pointer and a target; Specifying explicitly a type in an ALLOCATE statement. class(base_type), allocatable:: item .... allocate(extended_type:: item) Specifying a SOURCE or MOLD in the ALLOCATE statement. type(extended_type):: foo class(base_type), allocatable:: item .... allocate(item,source=foo)
S. Filippone (SATM) Modern Fortran OO Features IT4I, Ostrava, 2016 16 / 25 Polymorphism
Fine points: The CLASS specifier must appear for the passed object in all type-bound procedures (except those marked as FINAL); The CLASS specifier may or may not appear for other variables; Through a polymorphic variable you can only invoke methods of the declared type
S. Filippone (SATM) Modern Fortran OO Features IT4I, Ostrava, 2016 17 / 25 Polymorphism
The SELECT TYPE (aka type guard) construct allows fine discrimination among related types subroutine print_particle(p) class(particle)::p
call print_vector(’position’,p%position()) call print_vector(’momentum’,p%momentum())
select type (p) type is (charged_particle) print*,’Charge is:’,p%charge() class is (charged_particle) print*,’Charge is:’,p%charge() print*,’May have other features ’ type is (particle) print*,’Base particle type, nothing special ’ class default print*,’Unknown particle type’ end select end subroutine print_particle S. Filippone (SATM) Modern Fortran OO Features IT4I, Ostrava, 2016 18 / 25 Type inquiry functions
extends type of(a,b) True if the type of a is an extension of the type of b same type as(a,b) True if the type of a is an extension of the type of b
S. Filippone (SATM) Modern Fortran OO Features IT4I, Ostrava, 2016 19 / 25 The parent type component
type:: psb_base_sparse_mat ...... contains procedure, pass(a):: transp_1mat => psb_base_transp_1mat procedure, pass(a):: transp_2mat => psb_base_transp_2mat generic, public:: transp => transp_1mat, transp_2mat end type psb_base_sparse_mat
type, extends(psb_d_base_sparse_mat):: psb_d_coo_sparse_mat
contains procedure, pass(a):: transp_1mat => d_coo_transp_1mat end type
S. Filippone (SATM) Modern Fortran OO Features IT4I, Ostrava, 2016 20 / 25 The parent type component
subroutine d_coo_transp_1mat(a) implicit none class(psb_d_coo_sparse_mat), intent(inout)::a
integer(psb_ipk_), allocatable:: itemp(:) integer(psb_ipk_):: info
call a%psb_d_base_sparse_mat%transp() call move_alloc(a%ia,itemp) call move_alloc(a%ja,a%ia) call move_alloc(itemp,a%ja)
call a%set_sorted(.false.) call a%set_sort_status(psb_unsorted_) return end subroutine d_coo_transp_1mat
S. Filippone (SATM) Modern Fortran OO Features IT4I, Ostrava, 2016 21 / 25 abstract and deferred
A type can be defined as abstract, in which case it cannot be instantiated directly type, abstract:: file_handle contains procedure(open_file) , deferred, pass(handle):: open end type file_handle
abstract interface subroutine open_file(handle) import class(file_handle), intent(inout):: handle end subroutine open_file end interface
S. Filippone (SATM) Modern Fortran OO Features IT4I, Ostrava, 2016 22 / 25 Finalization If your data type requires specific cleanup upon deallocation, you can define your own method with the final keyword: type, extends(psb_d_ell_sparse_mat):: psb_d_elg_sparse_mat type(c_ptr):: deviceMat= c_null_ptr
contains final:: d_elg_finalize end type psb_d_elg_sparse_mat
......
subroutine d_elg_finalize(a) use elldev_mod implicit none type(psb_d_elg_sparse_mat), intent(inout)::a
if(c_associated(a%deviceMat)) & & call freeEllDevice(a%deviceMat) a%deviceMat= c_null_ptr end subroutine d_elg_finalize
S. Filippone (SATM) Modern Fortran OO Features IT4I, Ostrava, 2016 23 / 25 Style guidelines
1 Write code that comments itself: type(gas):: air real, parameter:: viscosity=1.52E-05 ! meters/sec if(.not.readFromDisk(air)) air= constructGas(viscosity) 2 Name all constants; 3 Make constants constant (parameter attribute); 4 Minimize global data; 5 Make global data constant; 6 Provide global type parameters, including precision specification;
S. Filippone (SATM) Modern Fortran OO Features IT4I, Ostrava, 2016 24 / 25 Style guidelines
7 Provide (conditional) debugging; 8 Declare INTENT for all arguments; 9 Avoid side effects, especially in FUNCTION 10 Make components PRIVATE 11 Use indentation (consistently) 12 Always prevent implicit typing
S. Filippone (SATM) Modern Fortran OO Features IT4I, Ostrava, 2016 25 / 25