4

I have two derived types (child1 and child2) that both extend from the same abstract type (type, abstract :: parent). The abstract type has a deferred bound procedure.

I want to call a subroutine that performs some stuff (performance critical) depending on the type of the child handed over as input. I can think of two options:

  • The subroutine takes the class(parent), intent(inout) :: type_in as input. Implementations for the children are then done within a select type (type_in) construct.
  • I write two subroutines, one with type(child1), intent(inout) :: type_in and one with type(child2), intent(inout) :: type_in and provide an explicit interface to overload the routine name.

The first option allows for implementations where the extension of the parent is not known at compile time, but that is not necessary in my case. It also saves some lines of code because only a part of it is different for the children.

My question is: Is there additional overhead in option one because I implemented the input as polymorphic data when the type is known at compile time?

g.b.
  • 347
  • 1
  • 5
  • You mention a deferred [type] bound procedure. Are the subroutines that you want to call the implementation in each extension of that deferred binding? If not, what is the relevance of that deferred binding? If you are starting with a polymorphic object, and you want behaviour to vary depending on dynamic type, then strongly prefer dispatch through a binding rather than select type. Vladimir's answer then deals with the overhead of the reference through that binding. – IanH Oct 02 '15 at 22:58
  • @IanH The deferred procedure is called within the subroutine. It is invoked within a big do-loop and it is the routine of my code which is called the most times (and most time consuming). At the moment, I use a select type construct and the do-loop is implemented for every case. I used a deferred procedure because the parent type is likely to be extended by other users and the interface should always look the same. Maybe I shouldn't be using deferred procedures (or type bound procedures) for the performance critical parts of my code. – g.b. Oct 03 '15 at 09:09
  • At the end of the day, whether the overhead of the "virtual call" (if there is one - that only applies if the object designator is polymorphic) that Vladimir discusses is material will depend on many things, such that you won't really know unless you measure. That aside, I would question a design where you are calling a type bound procedure of an object from within a SELECT TYPE block operating on that same object. Consider - if other users decide to extend the parent type, will they be able to do so without modifying the SELECT TYPE code? – IanH Oct 03 '15 at 10:46

1 Answers1

4

Yes, there is additional cost of a so call virtual call. A virtual method table (as it is called in other languages) is used and searched for the right procedure to call. The cost is likely to be similar to that of a virtual function call in C++, see https://stackoverflow.com/a/453001/721644

The compiler is sometimes able to find out which procedure is called by the binding even at compile time. For example, when the actual passed object is non-polymorphic. GCC has two flags -fdevirtualize and -fdevirtualize-speculatively (enabled with -O2, -O3, -Os) which convert virtual calls to direct calls. They are likely applicable to Fortran too.

Community
  • 1
  • 1
  • 1
    It will depend on the details of the implementation, but invoking a procedure with a polymorphic dummy argument typically requires the compiler to pass a descriptor. If the compiler doesn't already have such a descriptor (which may well be the case for a non-polymorphic actual argument) then there is also the overhead of constructing such a descriptor. – IanH Oct 03 '15 at 00:27