Constructors and `cfunction`


I just tried to get a C function pointer to a constructor, and was surprised when I got an error:

julia> struct Thing

julia> cfunction(Thing, Ref{Thing}, (Int,))
ERROR: closures are not yet c-callable
 [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?


Sounds like a bug.


OK, thanks, I’ll open an issue.