Modern Fortran OO Features Salvatore Filippone School of Aerospace, Transport and Manufacturing, salvatore.filippone@cranfield.ac.uk 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 Knuth Donald 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. module astronaut_class implicit none private! Hide everything by default public :: astronaut! Expose type & constructor integer,parameter :: max_string_length=100 type astronaut private character(len=max_string_length) :: greeting procedure :: greet! Public by default end type function greet(this) result(message) class(astronaut), intent(in) :: this character(len=max_string_length) :: message message = this%greeting end function end module program oo_hello_world use astronaut_class,only : astronaut type(astronaut) :: pilot pilot = astronaut( Hello, world! ) print *, pilot%greet() 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 module psb_base_mat_mod type :: psb_base_sparse_mat!> Row size integer(psb_ipk_), private :: m!> Col size integer(psb_ipk_), private :: n!> Matrix state: integer(psb_ipk_), private :: state integer(psb_ipk_), private :: duplicate logical, private :: triangle logical, private :: upper logical, private :: unitd logical, private :: sorted logical, private :: repeatable_updates=.false. function psb_base_get_fmt() result(res) implicit none character(len=5) :: res res = NULL end function psb_base_get_fmt! function psb_base_get_nrows(a) result(res) implicit none class(psb_base_sparse_mat), intent(in) :: a integer(psb_ipk_) :: res res = a%m end function psb_base_get_nrows procedure, pass(a) :: get_nrows => psb_base_get_nrows procedure, pass(a) :: get_ncols => psb_base_get_ncols procedure, nopass :: get_fmt => psb_base_get_fmt end type psb_base_sparse_mat function psb_base_get_ncols(a) result(res) implicit none class(psb_base_sparse_mat), intent(in) :: a integer(psb_ipk_) :: res res = a%n end function psb_base_get_ncols 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... 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 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 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 procedure :: speak => greet end type 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... 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 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 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 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