Is there an established pattern to "broadcast" a function, but without allocation of output? Just for the sake of side-effects. I.e., map
is to broadcast
as foreach
is to what?
I came up with this:
julia> function broadcast_foreach(op, args...)
bc = Base.broadcasted(op, args...)
foreach(x -> nothing, bc)
return nothing
end
broadcast_foreach (generic function with 1 method)
julia> xs = []
Any[]
julia> broadcast_foreach((xs, vs...) -> push!(xs, vs), Ref(xs), [2,3], [2,3])
julia> xs
2-element Vector{Any}:
(2, 2)
(3, 3)
julia> xs = []
Any[]
julia> broadcast_foreach((xs, vs...) -> push!(xs, vs), Ref(xs), [2,3], 1)
julia> xs
2-element Vector{Any}:
(2, 1)
(3, 1)
but not knowing as much about broadcasting machinery as I'd like to, there might be something existing I am overlooking.
One approach you could take is making a struct Null
such that writing data to it just throws away the data. Then you could do something like
Null() .= f.(x)
and broadcast Fusion should take care of everything.
I was thinking about that, too, but didn't know how to proceed. Some issues with broadcast style (I guess?):
julia> struct Null end
julia> Base.copyto!(::Null, bc::Broadcast.Broadcasted{Nothing}) = (foreach(_ -> nothing, bc); Null())
julia> f(xs, vs...) = push!(xs, vs)
f (generic function with 1 method)
julia> xs = []
Any[]
julia> Null() .= f.(Ref(xs), [2,3], 1)
ERROR: MethodError: no method matching ndims(::Type{Null})
...
I think you want to catch it earlier:
Broadcast.materialize!(dest::Null, bc::Base.Broadcast.Broadcasted) = (foreach(_ -> nothing, bc); Null())
It is not quite as efficient as ordinary broadcasting. IIRC there were some such issues with sum(::Broadcasted)
:
julia> x = rand(100, 100); y = rand(100, 100);
julia> @btime sin.($x ./ $y .+ 1);
min 77.958 μs, mean 86.330 μs (2 allocations, 78.17 KiB. GC mean 2.82%)
julia> @btime nothing .= sin.($x ./ $y .+ 1);
min 150.667 μs, mean 154.272 μs (0 allocations)
Hm. I would have thought that Broadcast.instantiate(bc)
would have fixed it but it didn't
Last updated: Nov 06 2024 at 04:40 UTC