Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

run-time polymorphism in fortran 2003

I'm writing some code in Fortran 2003 that does a lot of linear algebra with sparse matrices. I'm trying to exploit some of the more abstract features of the new standard so I have simpler programs without too much repeated code.

I have a procedure solver which takes in a matrix, some vectors, the tolerance for the iterative method used etc. I'm passing a pointer to a procedure called matvec to it; matvec is the subroutine we use for matrix-vector multiplications.

The problem is, sometimes matvec is a procedure which takes in extra arguments colorlist, color1, color2 above the usual ones sent to this procedure. I can think of several ways of dealing with this.

First idea: define two different abstract interfaces matvec1, matvec2 and two different solvers. This works but it means duplicating some code, which is just what I'm trying to avoid.

Another idea: keep the same abstract interface matvec, and make the extra arguments colorlist, color1, color2 optional. That means making them optional in every matvec routine -- even ones for which they're not really optional, and for routines where they're not even used at all. Pretty sure I'll go to hell if I do this.

I can think of plenty of other less than optimal solutions. I'd like some input on this -- I'm sure there's some elegant way to do it, I'm just not sure what it is.

like image 733
Daniel Shapero Avatar asked Mar 07 '13 06:03

Daniel Shapero


2 Answers

The question is really, whether the additional arguments must be passed every time the procedure is invoked (because they change between two invocations), or they can be initialized at some point and then just used in the function. In the later case you could create a class with an abstract interface, which defines your subroutine matvec with the essential arguments. You can then extend that class with more specialized ones, which can hold the additional options needed. They will still have to define the same matvec interface as the parent class (with the same argument list), but they can use the additional values stored in them when their matvec procedure is called.

You find a detailed example in this answer for a similar case (look for the second example showing module rechercheRacine).

like image 135
Bálint Aradi Avatar answered Nov 15 '22 05:11

Bálint Aradi


Instead of passing the procedure pointer as an explicit argument, you could put the various matvec routines behind a generic interface:

interface matvec
  module procedure matvec1, matvec2
end interface

Then your solver routine can just use the generic name with or without the extra arguments. The same approach can of course also be taken when using Bálint's suggested approach of defining a solver as a derived type with type-bound procedures:

type :: solver
  real, allocatable :: matrix(:,:), v1(:), v2(:)
contains
  procedure, pass :: matvec1
  procedure, pass :: matvec2
  generic :: matvec => matvec1, matvec2
end type

The main difference is that this does not use polymorphism to determine the correct procedure to invoke, but rather the characteristics of the dummy arguments.

I'm not sure of your intentions for the procedure pointer; if you wish to change its target at runtime (or perhaps assign some special meaning to its 'undefined' status), then pointers are the only way and all targets need to match the same abstract interface. If instead you just need to select one of several procedures based on their arguments, then you can exploit interfacing (my example) or overloading (Bálint's example). Each extension of a type can extend an inherited generic binding with new procedures, or overload an inherited specific binding.

like image 32
sigma Avatar answered Nov 15 '22 03:11

sigma