Difference between Base.product and Iterators.product?

They seem identical down to the documentation:

help?> Base.product
  product(iters...)

  Return an iterator over the product of several iterators. Each generated element
  is a tuple whose ith element comes from the ith argument iterator. The first
  iterator changes the fastest.

  Examples
  ≡≡≡≡≡≡≡≡≡≡

  julia> collect(Iterators.product(1:2, 3:5))
  2×3 Array{Tuple{Int64,Int64},2}:
   (1, 3)  (1, 4)  (1, 5)
   (2, 3)  (2, 4)  (2, 5)

help?> Iterators.product
  product(iters...)

  Return an iterator over the product of several iterators. Each generated element
  is a tuple whose ith element comes from the ith argument iterator. The first
  iterator changes the fastest.

  Examples
  ≡≡≡≡≡≡≡≡≡≡

  julia> collect(Iterators.product(1:2, 3:5))
  2×3 Array{Tuple{Int64,Int64},2}:
   (1, 3)  (1, 4)  (1, 5)
   (2, 3)  (2, 4)  (2, 5)

Indeed, they are the same:

julia> @which Base.product(1:2, 3:5)
product(iters...) in Base.Iterators at iterators.jl:898

julia> @which Iterators.product(1:2, 3:5)
product(iters...) in Base.Iterators at iterators.jl:898
1 Like

Why the duplication?

They’re not duplicated:

julia> Base.product === Iterators.product
true

Given that I use the 3-equals version, that means they are literally the same thing.

What’s happening is illustrated by this example:

julia> module Outer

       module Inner
       export myprod
       myprod(x, y) = x*y
       end

       using .Inner
       export Inner
       end
Main.Outer

julia> using .Outer

julia> Outer.myprod === Inner.myprod
true

But myprod itself is not visible without scoping:

julia> myprod
ERROR: UndefVarError: myprod not defined
6 Likes