I would say that the technique is general in that it does broadcast the operation, whatever it is (either +
or *
or /
). Of course, said operation has to be defined for the “scalar” operands, which is what the error is about in your examples.
To elaborate on your *
example:
julia> Ref([1,2]) .* [[3,4], [5,6]]
ERROR: MethodError: no method matching *(::Array{Int64,1}, ::Array{Int64,1})
does not work because [1,2] * [3,4]
does not work. In other words, the *
operator is correctly broadcasted, but this yields something which is not well defined. For example, the first item in the resulting array should be:
julia> [1,2]*[3,4]
ERROR: MethodError: no method matching *(::Array{Int64,1}, ::Array{Int64,1})
In order to perform the element-wise product of two arrays, you’d need to broadcast the *
operator a first time:
julia> [1,2].*[3,4]
2-element Array{Int64,1}:
3
8
Therefore, it is this element-wise *
operator which needs to be broadcasted a second time over arrays of arrays operands. One way of doing that is the following:
julia> ((x,y)->(x.*y)).(Ref([1,2]), [[3,4], [5,6]])
2-element Array{Array{Int64,1},1}:
[3, 8]
[5, 12]
which is merely a shortcut for something like:
julia> elemwise_prod(x, y) = x .* y
elemwise_prod (generic function with 1 method)
julia> elemwise_prod.(Ref([1,2]), [[3,4], [5,6]])
2-element Array{Array{Int64,1},1}:
[3, 8]
[5, 12]