I could not believe it in julia Version 0.6.0 (2017-06-19 13:05 UTC) I got
julia> max(Set([1]), Set([2]))
Set([2])
julia> max(Set([2]), Set([1]))
Set([1])
julia> min(Set([1]), Set([2]))
Set([1])
julia> min(Set([2]), Set([1]))
Set([2])
Now, Set{T} where T
does not have a canonical total order but a canonical partial order. Julia is aware of the difference, as the doc of <
includes:
Types with a canonical partial order should implement <, and types with a canonical total order should implement isless.
The implementation of of max (for non-numerical types) comes to max(x,y) = ifelse(y<x, x, y)
. This is perfectly valid for total orders but wrong for partial orders, as in the case of Set
.
So max(x, y) = ifelse(isless(y,x), x, y)
seems more appropriate to me. It would result in:
julia> max(Set([1]), Set([2]))
ERROR: MethodError: no method matching isless(::Set{Int64}, ::Set{Int64})
Stacktrace:
[1] max(::Set{Int64}, ::Set{Int64}) at ./REPL[115]:1
[2] macro expansion at ./REPL.jl:97 [inlined]
[3] (::Base.REPL.##1#2{Base.REPL.REPLBackend})() at ./event.jl:73
according to the imperative that it is better to obtain an error condition than to obtain an unreliable or arbitrary result.
In order to remove the Exception it would be possible to re-define the meaning of max
. It should return the lowest upper bound, if it exists. For total orders and numerical types, that is equivalent to âthe maximal elementâ. For non-numeric types implementing â<â instead of isless
the implementers should be encouraged to provide max
and min
to return âleast upper boundâ respectively âgreatest lower boundâ.
As far as I can see, in the Base package, only Set
and IntSet
are affected.
To following lines in base/set.jl
would solve the requirement:
max(x::AbstractSet{T}, y::AbstractSet{T}) where T = union(x, y)
min(x::AbstractSet{T}, y::AbstractSet{T}) where T = intersect(x, y)
as can be seen:
julia> min(Set([1]), Set([2]))
Set{Int64}()
julia> min(Set([2]), Set([1]))
Set{Int64}()
julia> max(Set([1]), Set([2]))
Set([2, 1])
julia> max(Set([2]), Set([1]))
Set([2, 1])