broadcasting for a composite type


#1

Working with v0.6.2, official release on linux, I was constructing a composite type that wraps Array. Then I ran into trouble when I tried to introduce broadcasting to the new type.

Here is my minimal working example:

julia> struct Vec
           data::Array{Float32, 1}
       end

julia> v = Vec(Float32[1, 2, 3])
Vec(Float32[1.0, 2.0, 3.0])

julia> Base.Broadcast._containertype(::Type{Vec}) = Vec

julia> Base.Broadcast.promote_containertype(::Type{Vec}, ::Type{Vec}) = Vec

julia> Base.Broadcast.promote_containertype(::Type{Vec}, _) = Vec

julia> Base.Broadcast.promote_containertype(_, ::Type{Vec}) = Vec

julia> Base.Broadcast.broadcast_c(::typeof(^), ::Type{Vec}, x::Number, y::Vec) = Vec(x .* y)

julia> 2.*v
ERROR: MethodError: no method matching broadcast_c(::##1#2, ::Type{Vec}, ::Vec)
Closest candidates are:
  broadcast_c(::Any, ::Type{Array}, ::Any, ::Any...) at broadcast.jl:312
  broadcast_c(::Any, ::Type{Nullable}, ::Any...) at broadcast.jl:324
  broadcast_c(::Any, ::Type{Any}, ::Any...) at broadcast.jl:337
  ...
Stacktrace:
 [1] broadcast(::Function, ::Vec) at ./broadcast.jl:455

I notice that broadcast works:

julia> broadcast(*, 2, v)
Vec(Float32[2.0, 4.0, 6.0])

I understand that this is not a brand new question.
I found some related posts:

The second one seems exactly the same as mine, and the reply indeed suggested the solution offered in the first one. However, as can be seen in the example above, it didn’t work apparently.

Is there anything I am missing?


#2

2 .* v.data works out of the box, and can be wrapped in Vec() if it needs to return a type Vec
You could probably write a function that takes various operators and applies them to v.data

function VecOp(x::Vec, op, param)
  r = Vec(op(x.data, param));
  return(r);
  end;
VecOp(v, (x,y)->x.*y, [1,2,3])
> Vec(Float32[1.0, 4.0, 9.0])

or

VecOp(v, *, 4)
> Vec(Float32[4.0, 8.0, 12.0])

It doesn’t like VecOp(v, .*, 4) though

.* is no longer a function


#3

First of all, thanks for the reply.

I must admit, I didn’t precisely state the purpose for which I posted the question.

I understand that by writing a separate function, I can achieve the goal of implementing the manipulation. Indeed I do have functions that do good job for arithmetic operators and their broadcast versions.

The point of this question is not related to this, however. Simply put, I’d like to understand what is wrong with the above code, which, to me, seems right (and which hopefully makes the other parts of the code significantly intuitive and clean).

What is especially strange to me is the following error message:

ERROR: MethodError: no method matching broadcast_c(::##1#2, ::Type{Vec}, ::Vec)

This apparently suggests that the interpretor is ignoring the first argument 2. Combined with the fact that broadcast(*, 2, v) works, this seems to imply that the problem is not at the definition of broadcast_c but at the interpretation of expressions like 2 .* v, but then I’m totally at a loss…


#4

The broadcast API is a moving target, and some of the information in those old posts is not necessarily relevant anymore. Start with the documentation.


#5

Thanks! I’ll try the latest version of julia and follow the documentation.