Skip to content

Reductions over one-element collections can return surprising values #34380

@mbauman

Description

@mbauman

Since reduce (and friends) are specified to call a two-argument function, the choice of what to do (and what to return) when there's only one element is rather arbitrary and can be surprising. A great motivating case here is reduce(vcat, X):

julia> reduce(vcat, [1])
1

julia> reduce(vcat, [1,2])
2-element Array{Int64,1}:
 1
 2

I really want reduce to just call vcat(1), but of course it cannot blindly do that in general. The solution is to provide an init. We do patch up this return value in a few notable cases — as this was required to get reduce to be type stable.

julia/base/reduce.jl

Lines 348 to 369 in 0ee3264

"""
Base.reduce_first(op, x)
The value to be returned when calling [`reduce`](@ref), [`foldl`](@ref`) or
[`foldr`](@ref) with reduction `op` over an iterator which contains a single element
`x`. This value may also used to initialise the recursion, so that `reduce(op, [x, y])`
may call `op(reduce_first(op, x), y)`.
The default is `x` for most types. The main purpose is to ensure type stability, so
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::SmallSigned) = Int(x)
reduce_first(::typeof(add_sum), x::SmallUnsigned) = UInt(x)
reduce_first(::typeof(mul_prod), x) = reduce_first(*, x)
reduce_first(::typeof(mul_prod), x::SmallSigned) = Int(x)
reduce_first(::typeof(mul_prod), x::SmallUnsigned) = UInt(x)

This function is nicely documented but doesn't appear in the manual. Should we just patch up vcat and hcat here for now? Or perhaps reduceing over 1-element collections without an init value should be just as much of an error as reduceing over empty ones.

Metadata

Metadata

Assignees

No one assigned

    Labels

    arrays[a, r, r, a, y, s]collectionsData structures holding multiple items, e.g. setsfoldsum, maximum, reduce, foldl, etc.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions