# Extend the domain of maximum and minimum to include empty collection?

**URL:** https://discourse.julialang.org/t/extend-the-domain-of-maximum-and-minimum-to-include-empty-collection/5135
**Category:** Internals & Design
**Tags:** question, proposal
**Created:** [July 30, 2017, 10:21am UTC](https://discourse.julialang.org/t/extend-the-domain-of-maximum-and-minimum-to-include-empty-collection/5135 "2017-07-30T10:21:20Z")
**Posts on this page:** 5
**Page:** 2

<div class="post-metadata">

### Author: ![klacru](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/klacru/32/27890_2.png) [@klacru](https://discourse.julialang.org/u/klacru)
#### Post date: [August 2, 2017, 6:25am UTC](https://discourse.julialang.org/t/extend-the-domain-of-maximum-and-minimum-to-include-empty-collection/5135/21 "2017-08-02T06:25:07Z")

</div>

Let me give a use case:  
There is a collection of classroom-courses with pupils of different grades. In order to elect the best-of-school pupil, the following procedure is defined: From each course select the pupil with the best marks. Add a bias according to the grade and select pupil with best sum of marks and bias. We assume better marks are represented by floating point numbers int he range between -1 and 1, the bias values between -0.2 and 0.2 only depend on the grade of the course and are based on statistics of the school principal.

Implementation:

```julia
struct Pupil
           marks::Float64
           gender::Symbol
end
struct Course
           bias::Float64
           pupils::Vector{Pupil}
 end

courses = [Course(0.2, [Pupil(0.7, :male), Pupil(0.8,:female)]), Course(-0.2, [Pupil(0.8, :male), Pupil(0.7,:male)])];
marks(p::Pupil) = p.marks
bestofclass(c::Course, gen::Symbol) = maximum(marks.(filter(p->gen == :all || p.gender == gen, c.pupils)))
bestofschool(cs::Vector{Course}, gen = :all) = maximum(c->bestofclass(c, gen) + c.bias, cs)

julia> bestofschool(courses)
1.0

julia> bestofschool(courses, :male)
0.8999999999999999

julia> bestofschool(courses, :female)
ERROR: ArgumentError: reducing over an empty collection is not allowed
Stacktrace:
 [1] _mapreduce(::Base.#identity, ::Base.#scalarmax, ::IndexLinear, ::Array{Float64,1}) at ./reduce.jl:265
 [2] bestofclass(::Course, ::Symbol) at ./REPL[9]:1
 [3] _mapreduce(::##7#8{Symbol}, ::Base.#scalarmax, ::IndexLinear, ::Array{Course,1}) at ./reduce.jl:273
 [4] bestofschool(::Array{Course,1}, ::Symbol) at ./REPL[10]:1
 [5] macro expansion at ./REPL.jl:97 [inlined]
 [6] (::Base.REPL.##1#2{Base.REPL.REPLBackend})() at ./event.jl:73

```

The last run fails, because there are no female pupils in one of the courses.  
See the results after with modified function:

```julia
julia> bestofschool(courses)
1.0
julia> bestofschool(courses, :male)
0.8999999999999999
julia> bestofschool(courses, :female)
1.0

```

---

<div class="post-metadata">

### Author: ![klacru](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/klacru/32/27890_2.png) [@klacru](https://discourse.julialang.org/u/klacru)
#### Post date: [August 3, 2017, 9:07am UTC](https://discourse.julialang.org/t/extend-the-domain-of-maximum-and-minimum-to-include-empty-collection/5135/22 "2017-08-03T09:07:45Z")

</div>

There seems some resistance and some technical difficulties to extend the domain of `maximum` or `minimum` to include empty collections.  
Conforming to a proposal

> [@max(x::T, y::T) and min must be commutative!](https://discourse.julialang.org/t/max-x-t-y-t-and-min-must-be-commutative/5165/11):
>
> Defining min and max to compute intersection and union has a certain appeal, but I don’t think it’s what people would really expect, and as noted would be inefficient. It seems more appropriate to introduce generic meet and join operations.

and

> [@max(x::T, y::T) and min must be commutative!](https://discourse.julialang.org/t/max-x-t-y-t-and-min-must-be-commutative/5165/15):
>
> The name join is already used for other purposes, without a corresponding meet, whereas supremum and infimum, sup and inf, lub and glb seem quite free (or if used in packages, perhaps mean more or less the same as proposed here).

I would propose to

- document the current behaviour of `maximum` and `minimum` and leave it as it is.
- implement new functions `supremum` and `infimum`, which behave equivalent for non-empty collections of totally ordered types, but cover the other cases as well.

---

<div class="post-metadata">

### Author: ![klacru](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/klacru/32/27890_2.png) [@klacru](https://discourse.julialang.org/u/klacru)
#### Post date: [August 3, 2017, 9:20am UTC](https://discourse.julialang.org/t/extend-the-domain-of-maximum-and-minimum-to-include-empty-collection/5135/23 "2017-08-03T09:20:36Z")

</div>

Proposal for the extension of the documentation for `maximum`:

```julia
help?> maximum
  maximum(itr)

  Returns the largest element in a `non-empty` collection.

  If itr is empty, throw exception of type ArgumentError.

  julia> maximum(-20.5:10)
  9.5
  julia> maximum([1,2,3])
  3
  `julia> maximum(UInt[])
  ERROR: ArgumentError: reducing over an empty collection is not allowed
`
julia> 

  maximum(A, dims)

  Compute the maximum value of an array over the given dimensions. See also the max(a,b) function
  to take the maximum of two or more arguments, which can be applied elementwise to arrays via
  max.(a,b).

...

 `maximum(f::Callable, a)`

  Returns the largest value of f.(a) or zero for a collection a.

  The collection must generally not be empty, with few exceptions.

  If a is not empty, return the largest value of f.(a). That is equal to maximum(f.(a)) but
  execution is more efficient.
  If a is empty and f is one of Base.abs or Base.abs2, return the zero value of the element type
  of a.

  If a is empty or has no element type or no zero of the element type is available, throw
  exception.

  julia> maximum(sin, [2pi, pi/2])
  1.0
  
  julia> maximum(abs2, Float64[])
  0.0
  
  julia> maximum(abs2, UInt[])
  0x0000000000000000
  
  julia> maximum(x->x^2, UInt[])
  ERROR: ArgumentError: reducing over an empty collection is not allowed
  
  julia> maximum(sin, Float64[])
  ERROR: ArgumentError: reducing over an empty collection is not allowed
  
  julia> maximum(abs, x for x in 1:0)
  ERROR: ArgumentError: reducing over an empty collection is not allowed
  
  julia> struct Bogus end
  julia> Base.zero(::Type{Bogus}) = 0.0
  julia> maximum(abs, Bogus[])
  ERROR: TypeError: _mapreduce: in typeassert, expected Bogus, got Float64
  
  julia> struct Bogus2 end
  julia> maximum(abs, Bogus2[])
  ERROR: MethodError: no method matching zero(::Type{Bogus2})

```

---

<div class="post-metadata">

### Author: ![ericproffitt](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ericproffitt/32/11590_2.png) [@ericproffitt](https://discourse.julialang.org/u/ericproffitt)
#### Post date: [December 21, 2019, 6:01pm UTC](https://discourse.julialang.org/t/extend-the-domain-of-maximum-and-minimum-to-include-empty-collection/5135/24 "2019-12-21T18:01:30Z")

</div>

So, has there been an official decision made on this?

I’m generally in agreement with @klacru, and was surprised when `maximum` and `minimum` of empty `AbstractFloat` vectors didn’t return `-Inf` and `Inf` (resp.).

---

<div class="post-metadata">

### Author: ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)
#### Post date: [December 22, 2019, 6:49am UTC](https://discourse.julialang.org/t/extend-the-domain-of-maximum-and-minimum-to-include-empty-collection/5135/25 "2019-12-22T06:49:23Z")

</div>

Without an issue or a PR, most questions like this just don’t get an “official” decision.

I guess that `minimum` and `maximum` are not defined for empty collections could be mentioned in their docstings, but the error message is already informative.

[Previous page](https://discourse.julialang.org/t/extend-the-domain-of-maximum-and-minimum-to-include-empty-collection/5135.md?page=1)
