Programming Julia for years, I have always missed a way to use double-broadcasting.
Ref is preventing a broadcast, but often one wants to also apply a broadcast operation to each element of an iterable. This can be done by encapsulating one of the two broadcasts in an (anonymous) function:
julia> a = [reshape(1:4,(2,2)) for _=1:3]; broadcast((x)->Float32.(x), a)
3-element Vector{Matrix{Float32}}:
[1.0 3.0; 2.0 4.0]
[1.0 3.0; 2.0 4.0]
[1.0 3.0; 2.0 4.0]
But this feels awkward and one often wishes to have access to a .. operator.
So I had a go at it:
function (..)(f, nargs...)
mydot(nargs2...)=f.(nargs2...)
mydot.(nargs...)
end
a = [reshape(1:4,(2,2)) for _=1:3]; Float32..(a)
3-element Vector{Matrix{Float32}}:
[1.0 3.0; 2.0 4.0]
[1.0 3.0; 2.0 4.0]
[1.0 3.0; 2.0 4.0]
I did not quite expected that this ends up to be that simple, but for some (great!) unknown reason the .. notation automatically worked in infix notation.
Can we not use this implementation as a general addition to the Julia Language? I am more than happy to write a PR (with help-file and tests), if agreed.
Of course there are many more applications than just this casting every element of arrays in a collection. For example adding a Tuple to each array of Tuples is another common use-case.
julia> a = [(1,2),(3,4),(5,6)]; ..(+,a,Ref((3,3)))
3-element Vector{Tuple{Int64, Int64}}:
(4, 5)
(6, 7)
(8, 9)
Maybe there is even a way to enable the notation a ..+ Ref((3,3))?
What do you think?
See also this somewhat related thread: