Map/pmap and scalar argument

Take this code:

function foo(arg1, arg2, arg3)
   arg1 + arg2 + arg3
end

map(foo, [1;2;3], [4;5;6], 5)

This code is equivalent to [foo(1, 4, 5)], the other values discarded.

Is this behavior desired for any reason? It doesn’t appear to be documented, and I naively thought that a scalar would be broadcasted.

If c was an array, there’s a DimensionMismatch error, so it isn’t as if it always takes the smallest set it can apply.

Thus, should map(foo, [1;2;3], [4;5;6], 5) throw an error, forcing the user to turn it into an array of the necessary size; or should it broadcast the scalar internally?

Same applies to pmap.

Checked Julia 1.3.0-rc3 as well as 1.2.

An even simpler MWE is

map(+, 1:2, 1)

I suspect it has to do with scalars being iterable, but I am not sure it is intended.

1 Like

My guess is that this is unintended. It happens because map calls zip, and zip stops iterating once the shortest iterator (i.e. the scalar) is exhausted. (This behavior of zip is documented.)

The reason it does not throw a DimensionMistmatch is that Base.IteratorSize(zip(1:2, 1)) hits a fallback function that simply returns SizeUnknown() and this causes the dimension check to be bypassed.

Making this an error would be breaking, but I’d say it’s worth it since any code that it breaks is likely to be buggy. Users should be forced to specify either map(+, first(1:2), 1) or map(+, 1:2, Iterators.repeated(1)) depending on what they meant.

1 Like

I still think the major issue is scalars being iterable. Eg

julia> Base.IteratorSize(typeof(1:2))
Base.HasShape{1}()

julia> Base.IteratorSize(Number)
Base.HasShape{0}()

and when Base.zip_iteratorsize falls back to Base.and_iteratorsize, the fallback case delivers a SizeUnknown().

I am not sure what the best way to fix this is, but I do think this is a bug, and fixing a bug is not considered a breaking change.

1 Like

Since you do consider it a bug, I’ll create an issue for it over on GitHub.

2 Likes