What is a pure function?

Ok this clause makes me a little uncomfortable answering, since I don’t know if I can claim this is not just a “convenience” but here you have a barebones example that has bugged me some time ago.

Let’s say you have a derived type and you want to define an algebra for it: you’ll need overload for +, for -, maybe some products etc.

Since Fortran does not currently support sealed types (so yes, probably in some cases the best fix would be that, but current is not there, so whatever), if you want to define such overloads as type bound operators (which is paramount from a software design perspective: you want the user to import the algebra with a use, only: derived_type_name statement alone, without the fear that he/she could forget about the operators) you are forced to declare the input arguments as class(derived_type_name) and not type(derived_type_name). Then you remain with the problem of how to declare the return value of the function, right?

As Brad says

functions are affected as much as subroutines from the impossibility to return polymorphic objects.

What I would very much like is a way to enforce that in function add(a, b) result(c)

  • a and b are of the same type (still polymorphic, but coupled)
  • c would be emitted with the same type

Any time I would need to (re)define what should happen to additional fields in a inheriting type I would just override these operators. Hence marking the procedure as non_overridable is not an option, right?

So what should I do? Return everytime the parent type? That is surely not what I want, in many cases. Define all these operators outside the derived type? Sure, but this poses the API issues delined above… and again, it would mean to give up polymorphism.

What remains… giving up the operator API and resorting to a type bound subroutine? Ok but then, again, I have to give up its purity! Now we can do impure elemental subroutines (I totally would want algebra operations to be elemental!) but I don’t expect them to be really optimized if not declared as pure, what’s the point then, if they are just compiled as loops over the arrays?

I had commented along these lines on a somewhat related issue in the j3 proposals repository:

The main question was if something like this would work in F2023

pure function polymorphic_sum(A,B) result(C)
   class(some_class),intent(in) :: A
   type(typeof(A)),intent(in)   :: B
   type(typeof(A)) :: C
   C = [some implementation of A + B]
end function