With the new @cfunction
macro, there is now the option to use $
syntax to create a runtime closure over a callable, which (I think, please correct me if this is wrong) can be safely used as follows:
cfun = @cfunction $identity Int (Int,) # a CFunction
GC.@preserve cfun begin
ptr = Base.unsafe_convert(Ptr{Cvoid}, Base.cconvert(Ptr{Cvoid}, cfun))
ccall(ptr, Int, (Int,), 42)
end
So far so good, but now I’m trying to write a generated function that uses @cfunction
. Here are two attempts:
@generated function makefun1(obj)
quote
@cfunction $obj Int (Int,)
end
end
cfun = makefun1(identity) # a Ptr{Cvoid}, not a CFunction!
@generated function makefun2(obj)
quote
@cfunction $(Expr(:$, obj)) Int (Int,)
end
end
cfun = makefun2(identity) # a CFunction, so far so good
GC.@preserve cfun begin
ptr = Base.unsafe_convert(Ptr{Cvoid}, Base.cconvert(Ptr{Cvoid}, cfun))
ccall(ptr, Int, (Int,), 42) # error!
end
The error I get with this last version is:
ERROR: MethodError: Cannot `convert` an object of type Int64 to an object of type typeof(identity)
Closest candidates are:
convert(::Type{T}, ::T) where T at essentials.jl:154
Stacktrace:
[1] typeof(identity)(::Int64) at ./deprecated.jl:473
[2] top-level scope at ./gcutils.jl:87
which happens because the type of obj
gets interpolated in the generated function.
How do I do this? I guess I’m just confused due to the two different meanings of $
.
(Note: the application is FunctionWrappers.jl; my PR for 1.0 support currently passes tests but just reimplements the old jl_function_ptr
call that was present in cfunction
on 0.6. I’m trying to get this part working (@rdeits’ branch).