Max and maximum: why the difference?

`max` operates only on its arguments*, and is only useful if the number of args is > 1.** `maximum` operates on a collection and only takes a second argument in specific cases.

Is there any reason why we couldn’t have a single-argument method on `max` that, if given a collection, returns the equivalent of `maximum`?

*`max` has deprecated behavior in that it will operate on collections in an element-wise order.

**This is inconsistent: `max(5)` returns (the possibly-expected) `5`, but `max([1,2,3])` does not return `[1,2,3]`, nor does `max("a")` return `a`.

3 Likes

This would be really confusing. It’s better to just use two functions rather than trying to guess what should the function do. See Merging `max` and `maximum` · Issue #11872 · JuliaLang/julia · GitHub

The deprecated behavior has been, well, deprecated so it’s irrelevant now.

It’s not inconsistent. The “inconsistency” is that some types are comparable and some are not.

The “inconsistency” is that some types are comparable and some are not.

I can understand that if you’re comparing two things. But what are you comparing with a single-argument `max`, and how is `max(x::Real) = x` useful?

And I swear it’s complete coincidence that I asked this question within 2 hours of @jeff.bezanson closing that issue out (I didn’t even know it existed).

It’s as useful as `+(::Real)` and it shouldn’t be assigned a meaning that is incompatible with what the function means otherwise.

Imagine a function like

`f(x...) = max(x...)+1`

I think people would be annoyed if this worked for `f(x,y,z)` and `f(x,y)` but then mysteriously failed on `f(x)`.

5 Likes
``````julia> max("a","b","c")
"c"

julia> max("a","b")
"b"

julia> max("a")
ERROR: MethodError: no method matching max(::String)
Closest candidates are:
max(::Any, ::Any) at operators.jl:348
max(::Any, ::Any, ::Any, ::Any...) at operators.jl:424
max(::BigFloat, ::BigFloat) at mpfr.jl:577
...

julia> f(x...) = max(x...) + 1
f (generic function with 1 method)

julia> f([1,2,3], [4,5,6], [7,8,9])
3-element Array{Int64,1}:
8
9
10

julia> f([1,2,3], [4,5,6])
3-element Array{Int64,1}:
5
6
7

julia> f([1,2,3])
ERROR: MethodError: no method matching max(::Array{Int64,1})
Closest candidates are:
max(::AbstractArray{T1<:Real,N} where N, ::Real) where T1<:Real at deprecated.jl:50
max(::AbstractArray{T1<:Real,N} where N, ::AbstractArray{T2<:Real,N} where N) where {T1<:Real, T2<:Real} at deprecated.jl:50
max(::Any, ::Any) at operators.jl:348
...
Stacktrace:
[1] f(::Array{Int64,1}, ::Vararg{Any,N} where N) at ./REPL[4]:1

``````

Yes. (Though, to be fair, this isn’t the behavior I’m suggesting for a single vector/collection.)

1 Like

The behavior of `max("a")` basically means that the current implementation is not consistent enough and should be fixed. It’s not an argument for making it even more inconsistent. The `max([1, 2, 3])` case is irrelavent.

2 Likes

You could just add square brackets to the `max` argument in that case:

``````f(x...) = max([x...])+1
``````

I would like to have just one function to get the maximum of a collection or several items.
The two functions always confuse me and i think that the dot-notation removes the ambiguities.

I think that the dot notation will allocate memory so won’t be efficient for large collections.

1 Like

One possible way is this:

``````f(x...) = (length(x) == 1 ? x[1] : max.(x...))+1
``````

Is there any reason why we couldn’t have a single-argument method on max that, if given a collection, returns the equivalent of maximum?

There was a long discussion in #4235. It explained the logic. Personally, I think there is no simple and intuitive reason for not choosing an unified `max` method.

From what I understand from related discussion, the drawbacks for using a unified `max` method are:
(1) A single `max` with keyword arguments method is run-time slower than the `max` + `maximum` combination. So a performance-wise issue.
(2) A single `max` method breaks the consistency of dot-call usages. For example, the `max` would work for both `max(scalar)` and `max(vector)`. Some developers argued that a single method accepts both scalar and vector input is confusing or redundant(use dot-call instead). Two other examples are `sin` and `clamp`, both of them do not accept vector input either.

IMHO, current implementation is explainable but not intuitive enough.

2 Likes