title: Does ccall really convert arguments passed by pointer?
body: <p>Considering a dynamic library with this native function that returns the sum of all even (32-bit unsigned) numbers in an array:</p>
  <pre class="lang-c prettyprint-override"><code>uint32_t sum_of_even(const uint32_t *numbers, size_t length);
  </code></pre>
  <p>The implementation of the function above was written in Rust as below, and packaged into a C dynamic library.</p>
  <pre class="lang-rust prettyprint-override"><code>use libc::size_t;
  use std::slice;
  
  #[no_mangle]
  pub extern &quot;C&quot; fn sum_of_even(n: *const u32, len: size_t) -&gt; u32 {
      let numbers = unsafe {
          assert!(!n.is_null());
          slice::from_raw_parts(n, len as usize)
      };
  
      numbers
          .iter()
          .filter(|&amp;v| v % 2 == 0)
          .sum()
  }
  </code></pre>
  <p>I wrote the following Julia (v1.0.1) wrapper function:</p>
  <pre><code>lib = Libdl.dlopen(libname)
  sumofeven_sym = Libdl.dlsym(lib, :sum_of_even)
  
  sumofeven(a) = ccall(
      sumofeven_sym,
      UInt32,
      (Ptr{UInt32}, Csize_t),
      a, length(a)
  )
  </code></pre>
  <p>The documentation states multiple times that arguments in <a href="https://docs.julialang.org/en/v1/base/c/#ccall" rel="nofollow noreferrer"><code>ccall</code></a> are converted to become compatible with the C function prototype (emphasis mine):</p>
  <blockquote>
  <p>Each <code>argvalue</code> to the <code>ccall</code> will be converted to the corresponding <code>argtype</code>, by automatic insertion of calls to <code>unsafe_convert(argtype, cconvert(argtype, argvalue))</code>. (See also the documentation for <a href="https://docs.julialang.org/en/v1/base/c/#Base.unsafe_convert" rel="nofollow noreferrer"><code>unsafe_convert</code></a> and <a href="https://docs.julialang.org/en/v1/base/c/#Base.cconvert" rel="nofollow noreferrer"><code>cconvert</code></a> for further details.) In most cases, <strong>this simply results in a call to <code>convert(argtype, argvalue)</code></strong>.</p>
  </blockquote>
  <p>And moreover, that when passing an <code>Array{T}</code> by <code>Ptr{U}</code> to a C function, the call is invalidated if the two types T and U are different, since no reinterpret cast is added (section <a href="https://docs.julialang.org/en/v1/manual/calling-c-and-fortran-code/#man-bits-types-1" rel="nofollow noreferrer">Bits Types</a>):</p>
  <blockquote>
  <p>When an array is passed to C as a <code>Ptr{T}</code> argument, it is not reinterpret-cast: <strong>Julia requires that the element type of the array matches <code>T</code></strong>, and the address of the first element is passed.</p>
  <p>Therefore, if an <code>Array</code> contains data in the wrong format, <strong>it will have to be explicitly converted</strong> using a call such as <code>trunc(Int32, a)</code>.</p>
  </blockquote>
  <p>However, this is seemingly not the case. If I deliberately pass an array with another type element:</p>
  <pre><code>println(sumofeven(Float32[1, 2, 3, 4, 5, 6]))
  </code></pre>
  <p>The program calls the C function with the array passed directly, without converting the values nor complaining about the different element types, resulting in either senseless output or a segmentation fault.</p>
  <p>If I redefine the function to accept a <code>Ref{UInt32}</code> instead of a <code>Ptr{UInt32}</code>, I am prevented from calling it with the array of floats:</p>
  <pre class="lang-none prettyprint-override"><code>ERROR: LoadError: MethodError: Cannot `convert` an object of type Array{Float32,1} to an object of type UInt32
  Closest candidates are:
    convert(::Type{T&lt;:Number}, !Matched::T&lt;:Number) where T&lt;:Number at number.jl:6
    convert(::Type{T&lt;:Number}, !Matched::Number) where T&lt;:Number at number.jl:7
    convert(::Type{T&lt;:Integer}, !Matched::Ptr) where T&lt;:Integer at pointer.jl:23
    ...
  </code></pre>
  <p>However, <code>Ref</code> was not designed for arrays.</p>
  <p>Making the example work with <code>Ptr{UInt32}</code> requires me to either specify <code>Array{UInt32}</code> as the type of input <code>a</code> (static enforcement), or <code>convert</code> the array first for a more flexible function.</p>
  <pre><code>sumofeven(a:: Array{UInt32}) = ccall( # ← either this
      sumofeven_sym,
      UInt32,
      (Ptr{UInt32}, Csize_t),
      convert(Array{UInt32}, a), # ← or this
      length(a))
  </code></pre>
  <p>With that, I still feel that there is a gap in my reasoning. What is the documentation really suggesting when it says that an array passed to C as a <code>Ptr{T}</code> is not reinterpret-cast? Why is Julia letting me pass an array of different element types without any explicit conversion?</p>