diff --git a/NEWS.md b/NEWS.md index e5d3619986d087..9c24f581104e63 100644 --- a/NEWS.md +++ b/NEWS.md @@ -8,6 +8,7 @@ New language features Language changes ---------------- +* `reduce`/`mapreduce` using `&` and `|` as an operator over empty collections of unknown element type will throw an error instead of returning `true`/`false` ([#31635], [#31837]). Multi-threading changes ----------------------- diff --git a/base/reduce.jl b/base/reduce.jl index 4113f9a7368434..02a0f654f0a0d6 100644 --- a/base/reduce.jl +++ b/base/reduce.jl @@ -54,7 +54,7 @@ end function mapfoldl_impl(f, op, nt::NamedTuple{()}, itr) y = iterate(itr) if y === nothing - return Base.mapreduce_empty_iter(f, op, itr, IteratorEltype(itr)) + return Base.mapreduce_empty(f, op, eltype(itr)) end (x, i) = y init = mapreduce_first(f, op, x) @@ -110,7 +110,7 @@ end function mapfoldr_impl(f, op, ::NamedTuple{()}, itr, i::Integer) if isempty(itr) - return Base.mapreduce_empty_iter(f, op, itr, IteratorEltype(itr)) + return Base.mapreduce_empty(f, op, eltype(itr)) end return mapfoldr_impl(f, op, (init=mapreduce_first(f, op, itr[i]),), itr, i-1) end @@ -228,9 +228,9 @@ with reduction `op` over an empty array with element type of `T`. If not defined, this will throw an `ArgumentError`. """ reduce_empty(op, T) = _empty_reduce_error() -reduce_empty(::typeof(+), T) = zero(T) +reduce_empty(::typeof(+), ::Type{<:Number}) = zero(T) reduce_empty(::typeof(+), ::Type{Bool}) = zero(Int) -reduce_empty(::typeof(*), T) = one(T) +reduce_empty(::typeof(*), ::Type{<:Number}) = one(T) reduce_empty(::typeof(*), ::Type{<:AbstractChar}) = "" reduce_empty(::typeof(&), ::Type{Bool}) = true reduce_empty(::typeof(|), ::Type{Bool}) = false @@ -256,13 +256,8 @@ mapreduce_empty(::typeof(identity), op, T) = reduce_empty(op, T) mapreduce_empty(::typeof(abs), op, T) = abs(reduce_empty(op, T)) mapreduce_empty(::typeof(abs2), op, T) = abs2(reduce_empty(op, T)) -mapreduce_empty(f::typeof(abs), ::typeof(max), T) = abs(zero(T)) -mapreduce_empty(f::typeof(abs2), ::typeof(max), T) = abs2(zero(T)) - -mapreduce_empty_iter(f, op, itr, ::HasEltype) = mapreduce_empty(f, op, eltype(itr)) -mapreduce_empty_iter(f, op::typeof(&), itr, ::EltypeUnknown) = true -mapreduce_empty_iter(f, op::typeof(|), itr, ::EltypeUnknown) = false -mapreduce_empty_iter(f, op, itr, ::EltypeUnknown) = _empty_reduce_error() +mapreduce_empty(::typeof(abs), ::typeof(max), T) = abs(zero(T)) +mapreduce_empty(::typeof(abs2), ::typeof(max), T) = abs2(zero(T)) # handling of single-element iterators """ diff --git a/test/syntax.jl b/test/syntax.jl index 85951185f4a57d..2f2291197e8dcf 100644 --- a/test/syntax.jl +++ b/test/syntax.jl @@ -287,7 +287,7 @@ call2(f,x,y) = f(x,y) @test (call2(42,1) do x,y; x+y+1 end) == 44 # definitions using comparison syntax -let a⊂b = reduce(&, x ∈ b for x in a) && length(b)>length(a) +let a⊂b = all(x ∈ b for x in a) && length(b)>length(a) @test [1,2] ⊂ [1,2,3,4] @test !([1,2] ⊂ [1,3,4]) @test !([1,2] ⊂ [1,2])