Fortran to Julia with a nested struct

This is following on from a question I had here https://discourse.julialang.org/t/fortran-to-julia-struct/79081.

I’m still trying to get Julia speaking to a Fortran library. My problem now is dealing with nested structs / derived types. An example (building on my previous MWE) is as follows.

Fortran code:

module fortranjulia
  
  use, intrinsic :: iso_c_binding
  implicit none

  type, bind(c) :: n_t
    integer(c_int) :: b1
  end type n_t

  type, bind(c) :: m_t
    integer(c_int)  :: a1
    real(c_double) :: a2(3)
    type(n_t) :: a3
    type(n_t) :: a4(2)
  end type m_t

contains

  subroutine print_mytype(m) bind(C, name = "print_mytype")
    type(m_t), intent(in) :: m
    print *, m%a1
    print *, m%a2
    print *, m%a3%b1
    print *, m%a4(1)%b1
    print *, m%a4(2)%b1
  end subroutine print_mytype

end module

The Julia code is

using StaticArrays
using Parameters

@with_kw mutable struct n_t
    b1::Cint = 99
end

@with_kw mutable struct m_t
    a1::Cint = 123456
    a2::SVector{3, Cdouble} = [1.0, 2.0, 3.0]
    a3::n_t = n_t()
    a4::SVector{2, n_t} = @SVector [n_t() for _ = 1:2]
end

m = m_t()
println("Julia")
println(m.a1)
println(m.a2)
println(m.a3.b1)
println(m.a4[1].b1)
println(m.a4[2].b1)

println("Fortran")
ccall((:print_mytype, "/path/to/fortran_julia"), Cvoid, (Ref{m_t},), m)

All the Fortran output from the nested struct is garbage.

Julia
123456
[1.0, 2.0, 3.0]
99
99
99
Fortran
      123456
   1.00000000000000        2.00000000000000        3.00000000000000     
  1594405776
       32554
  1594405792

Any help with this is appreciated. Thank you.

Don’t use mutable struct, use struct. The problem is that a3::n_t for a mutable struct is (loosely) analogous to struct nt *a3 in C.

The reason is that if you do something like:

m = m_t()
x = m.a3 # a "pointer" to the same object as m.a3, not a copy!
x.b1 = 2

then you need to get m.a3.b1 == 2 — this is what it means to have a mutable object, and it requires mutable-struct fields to be references (“pointers”), not stored inline as in a nested C struct or nested immutable struct.

Then, when you call the Fortran routine, construct an object mref = Ref{m_t}() to pass to the ccall, after which you can run m = mref[] to extract the struct data.

3 Likes