Trouble defining `broadcast` method between custom array type and `Number`


#1

Consider the following type definition for a custom array type (using 0.6.0-rc1):

struct MyArr{T, N} <: AbstractArray{T, N}
    x::Array{T, N}
end

Base.size(A::MyArr) = size(A.x)
Base.IndexStyle(::Type{T}) where {T <: MyArr} = Base.IndexLinear()
Base.getindex(A::MyArr, I...) = getindex(A.x, I...)
Base.broadcast(op, A::MyArr, other) = MyArr(broadcast(op, A.x, other))
Base.broadcast(op, other, A::MyArr) = MyArr(broadcast(op, other, A.x))


a = MyArr(rand(4))

The idea being that I want the result of a broadcast to be wrapped in a MyArr.

This works fine if I broadcast a MyArr with a Vector (a .+ rand(4)), but if I try a .+ 1.0 I get a standard Vector. Strangely running @which a .+ 1.0 gives me deprecated.jl:339, which seems to print a depwarn and call broadcast, but I don’t see the depwarn and when I call broadcast(+, a, 1.0) I get a wrapped MyArr as expected.

Not sure if this is a bug or I just need to do some more method magic to properly handle broadcasts on Numbers


#2

Broadcasting with literals lowers to broadcast(x->x+1.0, a). The solution is to hook into broadcast’s output array selection algorithm. I still haven’t bothered to figure out all the details, but check out Base.Broadcast.containertype.


#3

Thanks! I had a hunch if was some kind of lowering thing but didn’t know where to look.

I’ll look into it and report back what I find.


#4

So I ended up just defining:

Base.broadcast(op, A::MyArr) = MyArr(broadcast(op, A.x))

And that picked up the case that was being missed. I’m not sure if that’s the Right Way but it seems to pass my tests.