From a5306daf570d4df8359301a59508ed1b6b9d9a4a Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Wed, 21 May 2025 23:20:16 +0000 Subject: [PATCH] Use one-arg op form for reduce_first (Alternative #58490) In #58490, I said: ``` I considered a more aggressive change to make the generic fallback reduce_first(op, x) = op(x), but in discussion with Jeff, this was deemed too breaking, since it would add an assumption that op has a one-arg form. ``` However, what if we just checked whether `op` does have an appropriate method. This would generalize the fix also. For example, `reduce(+, list_of_arrays)` has the same aliasing issue that I complained about in #58490. In addition, this lets us remove the various reduce_first special cases, since the one arg reduction op has the correct behavior for all existing cases. --- base/reduce.jl | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/base/reduce.jl b/base/reduce.jl index 981cf41150553..58b3bc45fc4ec 100644 --- a/base/reduce.jl +++ b/base/reduce.jl @@ -17,6 +17,7 @@ add_sum(x, y) = x + y add_sum(x::BitSignedSmall, y::BitSignedSmall) = Int(x) + Int(y) add_sum(x::BitUnsignedSmall, y::BitUnsignedSmall) = UInt(x) + UInt(y) add_sum(x::Real, y::Real)::Real = x + y +add_sum(x) = +(x) """ Base.mul_prod(x, y) @@ -28,6 +29,7 @@ mul_prod(x, y) = x * y mul_prod(x::BitSignedSmall, y::BitSignedSmall) = Int(x) * Int(y) mul_prod(x::BitUnsignedSmall, y::BitUnsignedSmall) = UInt(x) * UInt(y) mul_prod(x::Real, y::Real)::Real = x * y +mul_prod(x) = *(x) and_all(x, y) = (x && y)::Bool or_any(x, y) = (x || y)::Bool @@ -397,18 +399,7 @@ The default is `x` for most types. The main purpose is to ensure type stability, additional methods should only be defined for cases where `op` gives a result with different types than its inputs. """ -reduce_first(op, x) = x -reduce_first(::typeof(+), x::Bool) = Int(x) -reduce_first(::typeof(*), x::AbstractChar) = string(x) - -reduce_first(::typeof(add_sum), x) = reduce_first(+, x) -reduce_first(::typeof(add_sum), x::BitSignedSmall) = Int(x) -reduce_first(::typeof(add_sum), x::BitUnsignedSmall) = UInt(x) -reduce_first(::typeof(mul_prod), x) = reduce_first(*, x) -reduce_first(::typeof(mul_prod), x::BitSignedSmall) = Int(x) -reduce_first(::typeof(mul_prod), x::BitUnsignedSmall) = UInt(x) -reduce_first(::typeof(vcat), x) = vcat(x) -reduce_first(::typeof(hcat), x) = hcat(x) +reduce_first(op, x) = applicable(op, x) ? op(x) : x """ Base.mapreduce_first(f, op, x)