Question about CONTAINS

I was talking about both. (W.r.t. to C++, I’m not sure if we agree for the same reason.)

The biggest downside is that internal procedures are not testable. You can use the include statement to circumvent this limitation, but then the contained procedures live in a different file. At this point you might as well put them in a module so you can then import both in your application and in a separate test driver.

Since internal procedures are difficult to test, my personal opinion is their use should be limited to adaptors (adjusting callback interfaces) or for simple helper functions which arguably don’t need testing.

If you need to have N-levels of nesting (where N > 1), it implies your function is so complex, you need multiple levels of encapsulation to tame it. The difference compared to modules being that none of that contain-ed code is reusable. This implies there is limited abstraction or generality. Now perhaps that’s just the way it is, and you do have a very deep procedure. It has a simple interface, but tons of stuff going on internally in different layers. With so much going on, something is bound to change at some point. But since we are depending on actual functions, and not just their abstract interfaces, the implementation details are not hidden. A change in one of the nested procedures will require recompilation of the encompassing procedures all the way up to the top. This seems like a violation of the SOLID principles. (single-responsibility principle, dependency-inversion principle).

Since sub doesn’t use host association, I don’t see much advantage in making it an internal procedure besides not polluting the namespace with an extra module. Since you are building an application, and not a library, the modules are thrown away anyways. Is it a sin to have a module with one procedure? Maybe at some point you decide you need a new subroutine sub2. If sub were in a module, you’d already have a suitable place waiting for you. You might call this design for change.

Perhaps sub could be made more useful elsewhere by making it more general?

subroutine sub(f,x)
   interface
      pure real function f(x)
         real, intent(in) :: x
      end function
   end interface
   real, intent(in) :: x
end subroutine

Now you could reuse sub with different concrete functions.

Perhaps f(x) is reusable, and we can import it in sub():

subroutine sub(x)
   use precious_functions, only: f => precious_parabola
   implicit none
   real, intent(in) :: x
   ! ... multiple references of f(xx)
end subroutine

Maybe I’m looking at this wrong. What benefit would lifting the constraint on nested functions bring, that a hierarchy of modules and submodules can’t?

1 Like