Skip to content

Commit

Permalink
combine reduce_empty methods for Union{} eltypes
Browse files Browse the repository at this point in the history
With #49470, these can all be dispatched to the same method now,
avoiding unnecessary code duplication for this case.
  • Loading branch information
vtjnash committed Nov 2, 2023
1 parent 2a84214 commit 4f92fe5
Show file tree
Hide file tree
Showing 3 changed files with 12 additions and 20 deletions.
3 changes: 0 additions & 3 deletions base/errorshow.jl
Original file line number Diff line number Diff line change
Expand Up @@ -258,9 +258,6 @@ function showerror(io::IO, ex::MethodError)
if f === Base.convert && length(arg_types_param) == 2 && !is_arg_types
f_is_function = true
show_convert_error(io, ex, arg_types_param)
elseif f === mapreduce_empty || f === reduce_empty
print(io, "reducing over an empty collection is not allowed; consider supplying `init` to the reducer")
show_candidates = false
elseif isempty(methods(f)) && isa(f, DataType) && isabstracttype(f)
print(io, "no constructors have been defined for ", f)
elseif isempty(methods(f)) && !isa(f, Function) && !isa(f, Type)
Expand Down
17 changes: 7 additions & 10 deletions base/reduce.jl
Original file line number Diff line number Diff line change
Expand Up @@ -316,10 +316,11 @@ pairwise_blocksize(::typeof(abs2), ::typeof(+)) = 4096


# handling empty arrays
_empty_reduce_error() = throw(ArgumentError("reducing over an empty collection is not allowed"))
_empty_reduce_error(@nospecialize(f), @nospecialize(T::Type)) = throw(ArgumentError("""
reducing with $f over an empty collection of element type $T is not allowed.
You may be able to prevent this error by supplying an `init` value to the reducer."""))
_empty_reduce_error() = throw(ArgumentError("reducing over an empty collection is not allowed; consider supplying `init` to the reducer"))
reduce_empty(f, T) = _empty_reduce_error()
mapreduce_empty(f, op, T) = _empty_reduce_error()
reduce_empty(f, ::Type{Union{}}, splat...) = _empty_reduce_error()
mapreduce_empty(f, op, ::Type{Union{}}, splat...) = _empty_reduce_error()

"""
Base.reduce_empty(op, T)
Expand All @@ -339,20 +340,16 @@ is generally ambiguous, and especially so when the element type is unknown).
As an alternative, consider supplying an `init` value to the reducer.
"""
reduce_empty(::typeof(+), ::Type{Union{}}) = _empty_reduce_error(+, Union{})
reduce_empty(::typeof(+), ::Type{T}) where {T} = zero(T)
reduce_empty(::typeof(+), ::Type{Bool}) = zero(Int)
reduce_empty(::typeof(*), ::Type{Union{}}) = _empty_reduce_error(*, Union{})
reduce_empty(::typeof(*), ::Type{T}) where {T} = one(T)
reduce_empty(::typeof(*), ::Type{<:AbstractChar}) = ""
reduce_empty(::typeof(&), ::Type{Bool}) = true
reduce_empty(::typeof(|), ::Type{Bool}) = false

reduce_empty(::typeof(add_sum), ::Type{Union{}}) = _empty_reduce_error(add_sum, Union{})
reduce_empty(::typeof(add_sum), ::Type{T}) where {T} = reduce_empty(+, T)
reduce_empty(::typeof(add_sum), ::Type{T}) where {T<:SmallSigned} = zero(Int)
reduce_empty(::typeof(add_sum), ::Type{T}) where {T<:SmallUnsigned} = zero(UInt)
reduce_empty(::typeof(mul_prod), ::Type{Union{}}) = _empty_reduce_error(mul_prod, Union{})
reduce_empty(::typeof(mul_prod), ::Type{T}) where {T} = reduce_empty(*, T)
reduce_empty(::typeof(mul_prod), ::Type{T}) where {T<:SmallSigned} = one(Int)
reduce_empty(::typeof(mul_prod), ::Type{T}) where {T<:SmallUnsigned} = one(UInt)
Expand Down Expand Up @@ -753,7 +750,7 @@ julia> maximum([1,2,3])
3
julia> maximum(())
ERROR: MethodError: reducing over an empty collection is not allowed; consider supplying `init` to the reducer
ERROR: ArgumentError: reducing over an empty collection is not allowed; consider supplying `init` to the reducer
Stacktrace:
[...]
Expand Down Expand Up @@ -785,7 +782,7 @@ julia> minimum([1,2,3])
1
julia> minimum([])
ERROR: MethodError: reducing over an empty collection is not allowed; consider supplying `init` to the reducer
ERROR: ArgumentError: reducing over an empty collection is not allowed; consider supplying `init` to the reducer
Stacktrace:
[...]
Expand Down
12 changes: 5 additions & 7 deletions test/reduce.jl
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ end
@test reduce(max, [8 6 7 5 3 0 9]) == 9
@test reduce(+, 1:5; init=1000) == (1000 + 1 + 2 + 3 + 4 + 5)
@test reduce(+, 1) == 1
@test_throws "reducing with * over an empty collection of element type Union{} is not allowed" reduce(*, ())
@test_throws "reducing with * over an empty collection of element type Union{} is not allowed" reduce(*, Union{}[])
@test_throws "reducing over an empty collection is not allowed" reduce(*, ())
@test_throws "reducing over an empty collection is not allowed" reduce(*, Union{}[])

# mapreduce
@test mapreduce(-, +, [-10 -9 -3]) == ((10 + 9) + 3)
Expand Down Expand Up @@ -91,8 +91,7 @@ end
@test mapreduce(abs2, *, Float64[]) === 1.0
@test mapreduce(abs2, max, Float64[]) === 0.0
@test mapreduce(abs, max, Float64[]) === 0.0
@test_throws ["reducing over an empty collection is not allowed",
"consider supplying `init`"] mapreduce(abs2, &, Float64[])
@test_throws "reducing over an empty collection is not allowed" mapreduce(abs2, &, Float64[])
@test_throws str -> !occursin("Closest candidates are", str) mapreduce(abs2, &, Float64[])
@test_throws "reducing over an empty collection is not allowed" mapreduce(abs2, |, Float64[])

Expand Down Expand Up @@ -144,9 +143,8 @@ fz = float(z)
@test sum(z) === 136
@test sum(fz) === 136.0

@test_throws "reducing with add_sum over an empty collection of element type Union{} is not allowed" sum(Union{}[])
@test_throws ["reducing over an empty collection is not allowed",
"consider supplying `init`"] sum(sin, Int[])
@test_throws "reducing over an empty collection is not allowed" sum(Union{}[])
@test_throws "reducing over an empty collection is not allowed" sum(sin, Int[])
@test sum(sin, 3) == sin(3.0)
@test sum(sin, [3]) == sin(3.0)
a = sum(sin, z)
Expand Down

0 comments on commit 4f92fe5

Please sign in to comment.