My question comes down to, should this be an error:
julia> Base.cconvert(Ref{Real}, Ptr{Integer}(1))
ERROR: MethodError: Cannot `convert` an object of type Ptr{Integer} to an object of type Real
This may have arisen from a call to the constructor Real(...),
since type constructors fall back to convert methods.
Stacktrace:
[1] Base.RefValue{Real}(::Ptr{Integer}) at .\refpointer.jl:42
[2] convert(::Type{Ref{Real}}, ::Ptr{Integer}) at .\refpointer.jl:53
[3] cconvert(::Type{T} where T, ::Ptr{Integer}) at .\essentials.jl:306
In the documentation it states that:
Here, the input
p
is declared to be of typeRef{gsl_permutation}
, meaning that the memory thatp
points to may be managed by Julia or by C. A pointer to memory allocated by C should be of typePtr{gsl_permutation}
, but it is convertable usingBase.cconvert()
and therefore can be used in the same (covariant) context of the input argument to a ccall.
I do follow that, but now I have the additional complication that I want to also allow Ref
s to subtypes. Mockup example:
abstract type Mammal end
abstract type Bear <: Mammal end
# here is a pointer that comes from a ccall
Ptr{Bear}(1)
# now it needs to go into a function that should work for any Mammal
# and since memory might also be owned by Julia, it is Ref
function staywarm(m::Ref{<:Mammal})
# so far so good, the Ptr{Bear} can enter this function
ccall(:zoo, Void, (Ref{Mammal},), m)
# but it cannot do the ccall since it will fail to Base.cconvert(Ref{Mammal}, m)
end
Looking in essentials.jl I see this hits the top line. If I change the Ptr
to Ref
in the second line it does work for me, but seems to cause chaos in the test suite.
cconvert(T::Type, x) = convert(T, x) # do the conversion eagerly in most cases
cconvert(::Type{<:Ptr}, x) = x # but defer the conversion to Ptr to unsafe_convert