Handling PyArray in Generic Functions: how to use `similar` and `copy` correctly

I’m working on making my functions generic to handle various types of arrays, including PyArray from PythonCall.jl. But I’ve encountered a problem with the similar function on PyArray types.

Here’s a simple example that highlights the problem:

using PythonCall

a = PyArray([1, 2])
b = similar(a)

function foo(a::V, b::V) where V<:AbstractArray
    (a, b)
end

foo(a, b) # fails

This call to foo generates the following error:

ERROR: MethodError: no method matching foo(::PyArray{Int64, 1, true, true, Int64}, ::Vector{Int64})

I initially discovered this issue while attempting to integrate a Julia package with Python using JuliaCall and calling a function of the form

bar(a::V; b::V=similar(a)) where V<:AbstractArray

My goal is to pass PyArray objects to my functions seamlessly, without needing to convert them to standard Array objects first. I’m glad for any suggestions. Thanks!

similar and copy do not (always) create arrays of the same type, i.e., the following also fails

a = view([1,2,3,4], 1:2)
b = similar(a)
foo(a, b)

A possible fix is to change the type signature of foo to foo(a::AbstractVector, b::AbstractVector). Unless there is a specific reason, it is often not necessary to restrict both arguments to the very same array type V, instead of just being both abstract arrays.

Thanks for the clarification, @bertschi. I hadn’t realized this was expected behavior of copy and similar.

As you suggested, I relaxed the type constraints on the relevant methods, and now the call from Python works without converting to standard arrays. Success!