# Converting Ptr of subtype to Ref of supertype in ccall

**URL:** <https://discourse.julialang.org/t/converting-ptr-of-subtype-to-ref-of-supertype-in-ccall/5620>\
**Category:** General Usage\
**Tags:** ccall\
**Created:** [August 28, 2017, 10:13pm UTC](https://discourse.julialang.org/t/converting-ptr-of-subtype-to-ref-of-supertype-in-ccall/5620 "2017-08-28T22:13:44Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![visr](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/visr/32/17204_2.png) [@visr](https://discourse.julialang.org/u/visr)\
**Post date:** [August 28, 2017, 10:13pm UTC](https://discourse.julialang.org/t/converting-ptr-of-subtype-to-ref-of-supertype-in-ccall/5620/1 "2017-08-28T22:13:44Z")

</div>

My question comes down to, should this be an error:

```julia
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](https://docs.julialang.org/en/latest/manual/calling-c-and-fortran-code/#Some-Examples-of-C-Wrappers-1) it states that:

> Here, the input `p` is declared to be of type `Ref{gsl_permutation}`, meaning that the memory that `p` points to may be managed by Julia or by C. A pointer to memory allocated by C should be of type `Ptr{gsl_permutation}`, but it is convertable using `Base.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:

```julia
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](https://github.com/JuliaLang/julia/blob/144c46be0ad98bc0dd40b3e3c5783b1cb12d2f92/base/essentials.jl#L306-L307) 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.

```julia
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
```

---

<div class="post-metadata">

**Author:** ![sdanisch](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sdanisch/32/1406_2.png) [@sdanisch](https://discourse.julialang.org/u/sdanisch)\
**Post date:** [August 29, 2017, 8:31am UTC](https://discourse.julialang.org/t/converting-ptr-of-subtype-to-ref-of-supertype-in-ccall/5620/2 "2017-08-29T08:31:39Z")

</div>

> [@visr](#):
>
> ccall(:zoo, Void, (Ref{Mammal},), m)

You can’t type the `ccall` with a Ref to an abstract type. What is C supposed to do with an Abstract Julia type?  
I think this can be changed to:

```julia
function staywarm(m::Ref{T}) where T <: Mammal
    ccall(:zoo, Void, (Ptr{T},), m)
end

```

Of course this means, that there must be a zoo function in C that works with all mammals…

---

<div class="post-metadata">

**Author:** ![visr](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/visr/32/17204_2.png) [@visr](https://discourse.julialang.org/u/visr)\
**Post date:** [August 29, 2017, 9:16am UTC](https://discourse.julialang.org/t/converting-ptr-of-subtype-to-ref-of-supertype-in-ccall/5620/3 "2017-08-29T09:16:39Z")

</div>

Thanks Simon, the `(Ptr{T},)` works indeed, but is that safe if the memory is owned by Julia? If I try your solution with `(Ref{T},)` I get:

```plaintext
error compiling staywarm: ccall: argument type Ref should have an element type, not Ref{T}

```

> [@sdanisch](#):
>
> What is C supposed to do with an Abstract Julia type?

In the end they are all just opaque pointers, but with the abstract types I try to tell Julia that functions like this:

> <https://github.com/JuliaGeo/GDAL.jl/blob/54160bbd0f49f7f1f80c33947b0016d7d19c4314/src/gdal_h.jl#L698>

Can accept subtypes of `GDALMajorObjectH`, which they can also in the C library.

> <https://github.com/JuliaGeo/GDAL.jl/blob/54160bbd0f49f7f1f80c33947b0016d7d19c4314/test/tutorial_raster.jl#L58>

Because Julia is told it is a subtype:

> <https://github.com/JuliaGeo/GDAL.jl/blob/54160bbd0f49f7f1f80c33947b0016d7d19c4314/src/types.jl#L3-L6>

This is working well as-is, but I wanted to switch the input types from `Ptr{T}` to `Ref{T}` because I believe it’s more general and possibly allow Julia owned objects to be used as input. Or am I mistaken in this?

---

<div class="post-metadata">

**Author:** ![sdanisch](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sdanisch/32/1406_2.png) [@sdanisch](https://discourse.julialang.org/u/sdanisch)\
**Post date:** [August 29, 2017, 11:38am UTC](https://discourse.julialang.org/t/converting-ptr-of-subtype-to-ref-of-supertype-in-ccall/5620/4 "2017-08-29T11:38:37Z")

</div>

> [@visr](#):
>
> If I try your solution with (Ref{T},) I get:

In a cruel turn of events, `Ref` is actually an abstract type! 😉

> [@visr](#):
>
> In the end they are all just opaque pointers, but with the abstract types I try to tell Julia that functions like this:

No, I meant how is `ccall` supposed to work with an Abstract type? The annotation in `ccall` is for annotating the function 1:1 like the types that you would put into a C header file - and you wouldn’t (usually) find an abstract Julia type in a C header.  
So since your C function expects a pointer, you need to use `Ptr` and not `Ref`.  
The pair of `ccall_type::Ptr{T} => ccall_arg::Ref{T}` is already the semantic for using Julia owned objects.  
So `Ref` is just a container for a Julia object which can be savely converted to a C `Ptr`, while still being owned by Julia.  
That’s also why Ref is abstract, because different julia object need different Ref types (e.g. an `Array`).

---

<div class="post-metadata">

**Author:** ![visr](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/visr/32/17204_2.png) [@visr](https://discourse.julialang.org/u/visr)\
**Post date:** [August 29, 2017, 1:35pm UTC](https://discourse.julialang.org/t/converting-ptr-of-subtype-to-ref-of-supertype-in-ccall/5620/5 "2017-08-29T13:35:00Z")

</div>

Many thanks, it’s starting to dawn on me. If it should be 1:1 I should just always use `Ptr{Void}` as the `ccall` input type right? Since in C these are all `typedef void *`

```julia
function staywarm(m::Ref{<:Mammal})
    ccall(:zoo, Void, (Ptr{Void},), m)
end

```

And then if I want to use it with the right C-compatible Julia structs instead:

```julia
struct Cat <: Mammal # I believe Simon likes cats
    a::UInt8
    b::Float64
end

```

Then I can use this function as follows:

```julia
a_cat = Cat(0x01, 2.0)
ref_cat = Ref(a_cat)
staywarm(ref_cat)

```
