Pass struct with mutable array field to ccall?

I need to call a C interface that has a struct argument like so:

typedef struct {
    double a[2];
} MyStruct;

I know I can could use the following Julia type to represent my data and pass that to ccall:

mutable struct MyJStruct
    a::NTuple{2, Float64}
end

x = MyJStruct((1., 2.))
ccall(f, Nothing, (MyJStruct,), x)

However, the MyJStruct type wouldn’t be useful to me in Julia. I frequently need to edit the values in the array in the type, which of course I can’t do when it’s represented as a Tuple. I can’t find a way to get a mutable type to work there.

Does the type of thing passed to ccall have to be a bits type and immutable? If so, is there some other way to do what I’m trying to do, like derive an immutable bits type from my mutable one?

Obviously, this is a tiny example, and my real type has many fields that are arrays of known length, hence I despair of having to create parallel types by hand or something like that.

Maybe you could use a StaticArrays.MVector{2, Float64}?

Hi Twan, and thanks. I tried an MVector, and that didn’t work. I filled it with data, but over on the C side, all I saw was a bunch of 0s. When I use an SVector, it works (the data is carried over to C correclty), but of course that’s not mutable and so still isn’t useful here. I confirmed that the type is a bits type when using an SVector, but not when using an MVector (I don’t know the internals of StaticArrays except that it uses tuples).

No it won’t work with any mutable types. You should be able to mutate that field just fine with an immutable type though. Unless you need concurrent access of different array element svector should work.

Thanks @yuyichao. An SVector in fact gets the data over to C correctly, but it fundamentally fails my use case: I need to be able to edit fields and indices of these types in Julia and then send them over to C. Am I supposed to have a mutable type that I use in Julia, then a parallel type that’s immutable but equivalent (e.g., SVector in the immutable version instead of array or MVector in the mutable one) and then have a conversion from the mutable type to the immutable one so that I can send the data over to C? And then, after the ccall, a conversion back from immutable to mutable so I can continue using things in Julia? This feels excessive.

Is there any other way I can “just gather my bits together to send them over”?

No there’s no failure at all and you don’t need two types. Again, you just mutate the field and not the object stored in the field, same way you reassign a variable that hold a immutable object. Please read the document of svector for the helper functions that allow you to construct an object with one of the elements changed.

Thanks again, @yuyichao. I read more into the StaticArrays doc. If I understand you correctly, you mean to use an SVector for the field along with setindex (no exclamation) for the “mutation”:

using StaticArrays

mutable struct MyJStruct
    a::SVector{2, Float64}
end

# Create our type.
x = MyJStruct([1., 2.])

# This would fail.
# x.a[1] = 3.

# This works as long as my struct type is mutable.
x.a = setindex(x.a, 3., 1)

display(x.a[1])
display(isbits(x))

In this way, I’m changing the index of the thing that I care about. Here MyJStruct would have to be mutable too, and it’s not a bits type. Is this what you’re suggesting?

That seems to conflict with what you were saying above, that I’ll need all immutables. It does, however, still seem to send this data over to C the right way.

Yes the type with that mutable field needs to be mutable and I don’t think I’ve said anything about it above since you’ve got that part fine in the first post.