I just tried to get a C function pointer to a constructor, and was surprised when I got an error:
julia> struct Thing
x::Int
end
julia> cfunction(Thing, Ref{Thing}, (Int,))
ERROR: closures are not yet c-callable
Stacktrace:
[1] cfunction(::Type{T} where T, ::Type{T} where T, ::Tuple{DataType}) at ./c.jl:24
Can someone please explain why that doesn’t work? Do I have an error, or is this expected? Also, what do closures have to do with this?
Interestingly, if I wrap the call to the constructor in another function, I can get a C function pointer to that.
julia> thing(x) = Thing(x)
thing (generic function with 1 method)
julia> cfunction(thing, Ref{Thing}, (Int,))
Ptr{Void} @0x0000000125f77ef0
Thanks in advance for the help!
A few follow on questions. All of the examples of cfunction
that I can find return Cdouble
or Cvoid
. Assuming I can solve my issues above and call a constructor with a cfunction
, who is responsible for freeing the memory pointed to by the return value? Is the returned value just a jl_value_t *
that has been cast to my specified return type and is managed by the Julia garbage collector?
For nonleaf return type the return value is a pointer. There’s no cast since it’s a c specific concept. The GC is responsible for freezing it and you are responsible for rooting it so that GC doesn’t do it too early.
So can I cast the return type to a jl_value_t *
? I actually need to keep the value around, and so I think I can’t just use JL_GC_PUSH1
on it. Instead, I was thinking of doing:
jl_set_const(jl_main_module, jl_gensym(), (jl_value_t *)the_object);
Julia doesn’t care how you use it in c so any c cast on it is fine. Setting it as a module field does not guarantee pointer validity for immutable types. You can use a Vector{Any}
though, which should also be significantly simpler for cleanup.
Thanks for the help! Do you have any comments on what is going on in my original question, where I try to call cfunction
on a constructor?
OK, thanks, I’ll open an issue.