MEGMS logo - go to the home page
  1. Home

    1. About Us

    2. Services

    3. MEGS_Log

    4. CoalLog tools

    5. Fortran Tools

      1. FF08Depends

      2. FF08Diff

      3. FF08FixedFormForEver

      4. FF08Obfuscate

      5. Internal test utilities

      6. aniso_varying_string

      7. Direct2D API bindings

      8. Fortran shared pointers

    6. Contact Us

  2. Site map

"Let's model me a mine"

M.E.G.M.S.


Mining & Exploration Geological Modelling Services

Previous topic Parent topic Home topic

Fortran shared pointers

A shared pointer is a concept that is useful in a situation where there can be multiple references to a particular object, the object must continue to exist while any references to it are extant and the object must cease to exist when no references to it are extant. A shared pointer in this situation acts as the reference, with coordination between shared pointers that reference the same object to manage the lifetime of the object.

A zip archive of source code that shows how a generic shared pointer can be implemented in a source library in Fortran 2008 is available under an Apache 2.0 licence, and can be found at www.megms.com.au/download/shared-pointers.zip (revision 2223 from 2016-06-23). This particular implementation uses reference counting. The generic nature is achieved by using INCLUDE to bring source into the scope of a module that expects the referenced object to be of a type named object_type.

Two variants are provided, one that permits weak references to the referenced object, and one that does not. Weak references do not prolong the life of the referenced object, but can be used to test the existence of the referenced object. They can be used to break reference cycles that result in objects existing indefinitely, even in the case that there are no references to objects in the cycle outside of the objects themselves. There is a small amount of overhead associated with the support for weak references.

The shared pointer functionality is encapsulated in a type named SharedPointer, while the weak reference functionality is in a type named WeakPointer. Note that SharedPointer and WeakPointer objects are not (typically) Fortran pointers (i.e. objects with the POINTER attribute) - instead they are wrappers around a Fortran pointer. Fortran pointers and Fortran pointer components are used to access the referenced object from a SharedPointer object.

Both provided variants internally reference the object using a Fortran pointer that is a polymorphic scalar. Other variants are possible and likely useful - using a non-polymorphic pointer, using a pointer to an object with some specified rank, but a polymorphic scalar is a reasonably general case.

The filename of the source to include for the variant that does not support weak pointers is PolyScalarSharedPointer.i90, while the filename for the variant that does support weak pointers is PolyScalarWeakSharedPointer.i90. The example programs for each variant are named similarly.

The means by which the source code for the SharedPointer type is used means that there can only be one SharedPointer type (and WeakPointer too, where applicable) defined in a particular module. This also means that each definition of a SharedPointer type is a distinct type. In the event that it is needed to have more than one SharedPointer types accessible in the same scope, then use renaming must be used to rename all the types to unique names.

Operations that mix different SharedPointer types will not be permitted by the compiler. This includes operations that might otherwise make sense given the type hierarchy of the referenced types - i.e. you cannot assign a SharedPointer object that references an extension type to a SharedPointer object that expects to reference a parent type, even though such a pointer assignment operation is permitted using Fortran pointers.

A brief example of how the source code is used:

MODULE SharedPointerModule
  ! The included code requires that the type being referenced be 
  ! known in the current scope by the name `object_type`.  If the 
  ! type is defined in another module, use renaming can be used 
  ! to achieve this.
  USE SomeOtherModule, object_type => type_for_referenced_object
  IMPLICIT NONE     ! If desired.
  PRIVATE           ! If desired.
  
  ! These are the identifiers defined by the included source 
  ! below.  Because the default accessibility of this module is 
  ! PRIVATE, if it is desired that scopes that USE this module have 
  ! access to these identifiers then they need to be explicitly 
  ! specified to be PUBLIC.
  PUBLIC :: SharedPointer, Acquire, Get
  
  ! The include line must come at the end of the specification part 
  ! of the module, before any module subprograms  The included
  ! source has the CONTAINS statement that separates the specifcation 
  ! part and module subprogram part of the module.
  INCLUDE 'PolyScalarSharedPointer.i90'
  
  ! Other module subprograms could go here.
  SUBROUTINE example
    ! A shared pointer for referencing objects of type object_type.
    TYPE(SharedPointer) :: sp
    ! A temporary Fortran pointer used to supply the object to the 
    ! shared pointer.
    CLASS(object_type), POINTER :: tmp
    
    ! Allocate the Fortran pointer.
    ALLOCATE(tmp)
    
    ! Place control of the lifetime of the object with a shared pointer.
    sp = SharedPointer(tmp)
    
    ! The object that was originally referenced by `tmp` will exist 
    ! until all there are no more SharedPointer objects referencing 
    ! the object.  
    !
    ! In the meantime the referenced object can be accessed using the 
    ! `Item` component of a shared pointer object, or via the Get 
    ! generic function that has a Fortran pointer result.
    sp%Item = ...
    Get(sp) = ...
    
    ! Other shared pointers referencing the same object can be created 
    ! using intrinsic assignment.
    BLOCK
      TYPE(SharedPointer) :: sp_other
      sp_other = sp
      ! You can explicitly set a shared pointer to not reference 
      ! any object by using the structure constructor with 
      ! no component specifiers.
      sp_other = SharedPointer()
    END BLOCK
    
    ! In this case the shared pointer `sp` is finalized at the 
    ! end of this procedure because it is an unsaved local variable.  
    ! When it is finalized it will cease to reference an object.  In 
    ! this example there are no other shared pointers referencing that 
    ! object so the object that was originally associated with the 
    ! `tmp` Fortran pointer will be automatically deallocated.
  END SUBROUTINE example
END MODULE SharedPointerModule

An alternative to using the SharedPointer generic function to construct a SharedPointer object is to use the Acquire generic subroutine.

The IsAssociated generic function can be used to test whether a SharedPointer or a WeakPointer object currently references an extant object.

If the shared pointer references an object, the Get generic function will return a Fortran pointer to the object. The Fortran 2008 feature that permits a function-reference with a data pointer result to designate a variable then permits a reference to this function to appear on the left hand side of an assignment expression, or it can be used in an expression.

It is possible to break the SharedPointer encapsulation using certain language features - see the "evil" internal procedures in the example main programs for elaboration:

Building from source

The source code should be compilable by a Fortran 2008 compiler.

Intel Visual Fortran 17.0 beta was the compiler used for development. With that compiler, the /standard-semantics switch (or its equivalent on non-Windows platforms) is required to compile the example programs.

Note that gfortran current trunk (at the time of writing version 7.0.0 20160615 (experimental)) cannot be used to compile the example programs (and likely any program that includes the source) due to PR71580.

Feedback

Questions, queries and quibbles can be sent to ff08@megms.com.au.