I have a large Fortran code base for which I am trying to write a Python interface. I decided I would go the Cython route. However, I have derived types that are not C-interoperable. As an example,
type :: SomeType
real, allocatable :: not_interoperable
[other members]
contains
procedure :: init
end type
...
subroutine init(this) bind(c)
class(SomeType), intent(inout) :: this
...
end subroutine init
I would be completely happy not being able to access the member not_interoperable from Python, and would actually prefer not to expose it to the user anyway. i.e. some python class that includes only the other members would be perfectly fine, as long as functions inside Fortran can still "see" them. Here, the compiler fails because init has a polymorphic dummy argument. I can remove init as a type-bound procedure, and then make the change class(SomeType) -> type(SomeType), but then I still get the error that this is a dummy argument to a bind(c) procedure but is not C interoperable because the derived type is not C interoperable.
Is there any way around this? The only solution I can see is removing all non-C-interoperable members out of SomeType and making them global/module variables in the Fortran code, but I'd rather avoid that. Basically, I want a way to hide variables from Python (like those that are not C interoperable) while still keeping the Fortran code modular/preventing global variables.
Some more details:
My program roughly works as:
type(SomeType) :: instance
instance%init() ! no input arguments, but reads a file
instance%do_some_stuff()
instance%do_stuff_with_args(...) ! args are all C-interoperable
instance%finalize()
I would like a similar workflow in Python
from FortranModule import SomeType
instance = SomeType(...) # does not read a file, variables passed directly
instance.do_stuff()
instance.member = 3
instance.do_stuff_with_args(...)
instance.finalize()
But in Python, not_interoperable is never accessed. I want my Fortran code to still have it and use it, and it is still affected by SomeType%init, but I do not want/need it in Python. In principle I guess I can hide it as a global variable which gets modified by this function, but then (a) I can only have one instance and (b) I don't like global variables as a general rule (general consensus is that it reduces modularity and maintainability).
Also, just for clarity: I have a lot of non-interoperable types, and they are not as simple as real, allocatable, so rewriting all of them is not really realistic.
AFAIK there's no way to interoperate with C a derived type containing allocatable component). A solution is to expose to C only an opaque handle (void* C pointer) to a derived type instance. Then there's the choice to keep the components completely hidden from C, or to give C some pointers to them.
Illustration code:
Fortran part:
C part:
Result:
However, managing C pointers from Python is maybe not convenient/possible (I don't know enough of python...). Then, instead of returning void* pointer handle, one can return identifiers, which refer to instances in a global array:
C part: