Working with @cfunction (and parametric types)



To make a package v0.7 deprecation warning free, i recently moved the cfunction s into the @cfunction syntax and got caught on

ERROR: LoadError: could not evaluate cfunction argument type (it might depend on a local variable)

which seems to be correct, the cfunction is

get_stream_callback(T) = @cfunction write_to_stream_callback  Int32 (Ref{T}, Ptr{UInt8}, UInt32)

with T from

function CairoPDFSurface(stream::T, w::Real, h::Real) where {T<:IO}
    callback = get_stream_callback(T)
    ptr = ccall((:cairo_pdf_surface_create_for_stream,_jl_libcairo), Ptr{Nothing},
                (Ptr{Nothing}, Any, Float64, Float64), callback, stream, w, h)
    CairoSurface(ptr, w, h)

I understand, that the cfunction macro needs a concrete(?) type, but does this mean i have to rewrite the function - and drop the parametric type?


The only workaround I’m aware of is to make your function an @generated function so that it can produce literal types for ccall. For example:

@generated function foo(x::T) where T
    ccall(..., ..., (Ref{$T},), x)

Edit: sorry, wasn’t paying careful enough attention and mixed up my ccalls and cfunctions. The above is probably not correct.



get_stream_callback(::Type{T}) where {T} = @cfunction write_to_stream_callback  Int32 (Ref{T}, Ptr{UInt8}, UInt32)


btw: Thank you. There was a race condition as David Anthoff asked the same question also on slack … but the solution converged.


That shouldn’t be necessary for ccall either — the rules for cfunction for v0.7 are now largely brought in line with those for ccall from v0.6. In particular, Kristoffer’s solution is correct for both.