On a user level, I prefer to use map when f is somehow complicated. It’s usually either when you need to write it as an anonymous function, or when you can’t use syntax sugar and have to call methods explicitly, or when function is so complicated that you want to use do syntax.
Example 1:
f(x, y) = x + y
v = [1, 2, 3]
map(x -> f(x, 1), v)
# vs
(x -> f(x, 1)).(v)
Example 2
v = [(1, 1), (2, 2), (3, 3)]
map(x -> x[2], v)
# vs
getindex.(v, 2)
Example 3:
v = [(0, 1), (1, 2), (2, 3)]
map(v) do x
println(v[1])
v[2]*v[2]
end
In all other cases, broadcasting is usually easier to read and use.
map (or a comprehension) is probably faster if seq is a generic iterable collection rather than an array, since broadcasting first calls collect to convert iterables into arrays. For example:
julia> @btime sqrt.(i^2 for i in 1:100);
325.522 ns (2 allocations: 1.75 KiB)
julia> @btime map(sqrt, i^2 for i in 1:100);
235.057 ns (1 allocation: 896 bytes)
Notice that the memory allocation is doubled in the broadcast case, because of the extra array allocated by collect.
Yeah, you are right, not the best illustration. What I was trying to say, there can be situations, when you have to write some sort of anonymous function. Maybe better example is hand-written implementation of the sign function
v = [-10, 0, 10]
map(x -> x > 0 ? 1 : x < 0 ? -1 : 0, v)
So broadcasting will . actually convert seq to an array, then eventually create and return something of the type that seq originally was, and then map directly creates a collection of the same type as the original seq?
Thanks for pointing this out. I would have expected that map should expect matching dimensions. I think having a “strict map” can also be a good thing to avoid unexpected behavior if you accidentally pass it parameters of different sizes, especially for users that are coming from / used to Python’s map behavior.
Huh. This is weird. I thought mean.(tdist) and broadcast(mean, tdist) were exactly identical, that the former was just syntax sugar for the latter. Apparently not:
As for why dot broadcast is faster, it appears to hit julia/broadcast.jl at v1.8.2 · JuliaLang/julia · GitHub in materialize. This unrolls the tuple, which avoids a dynamic dispatch per element and allows for a fully type stable (i.e. not boxed) return value.