Skip to content

Commit a17db2b

Browse files
Make DefaultStable and DefaultUnstable dispatchable and display without internals (#56661)
Previously, `DEFAULT_STABLE` was a giant chain of algorithms reflecting the full sorting dispatch system. Now, it's simply `DefaultStable()`. This has a few minor impacts: Previously, the public binding `Base.Sort.DEFAULT_STABLE` documented non-public implementation details of sorting dispatch in its extended help with a caviat that they are internal. Now, `Base.Sort.DEFAULT_STABLE` refers to the non-public binding `Base.Sort.DefaultStable` and implementation details are documented there with a warning that they are non-public. Previously, dispatching on `Base.Sort.DEFAULT_STABLE` required writing `::typeof(Base.Sort.DEFAULT_STABLE)` whereas now one could alternatively dispatch on the (internal) type `Base.Sort.DefaultStable`. Previously `Base.Sort.DEFAULT_STABLE === Base.Sort.DEFAULT_UNSTABLE` so when writing sorting algorithms for custom collections it was impossible to determine if the user asked for a stable algorithm. Now `DEFAULT_STABLE` is `DefaultStable()` and `DEFAULT_UNSTABLE` is `DefaultUnstable()`. Both the algorithms expand to the same large chain of algorithms `_DEFAULT_ALGORITHMS_FOR_VECTORS` but it is possible to intercept them before that happens. `Base.Sort.DEFAULT_STABLE` now prints as `DefaultStable()` instead of ```julia-repl julia> Base.Sort.DEFAULT_STABLE Base.Sort.SubArrayOptimization( Base.Sort.MissingOptimization( Base.Sort.BoolOptimization( Base.Sort.Small{10}( Base.Sort.InsertionSortAlg(), Base.Sort.IEEEFloatOptimization( Base.Sort.IsUIntMappable( Base.Sort.Small{40}( Base.Sort.InsertionSortAlg(), Base.Sort.CheckSorted( Base.Sort.ComputeExtrema( Base.Sort.ConsiderCountingSort( Base.Sort.CountingSort(), Base.Sort.ConsiderRadixSort( Base.Sort.RadixSort(), Base.Sort.Small{80}( Base.Sort.InsertionSortAlg(), Base.Sort.ScratchQuickSort(missing, missing, Base.Sort.InsertionSortAlg()))))))), Base.Sort.StableCheckSorted( Base.Sort.ScratchQuickSort(missing, missing, Base.Sort.InsertionSortAlg())))))))) ``` Factored out of #54494 at Triage's request (the git history reflects this history). --------- Co-authored-by: Lars Göttgens <[email protected]>
1 parent ea82538 commit a17db2b

File tree

2 files changed

+50
-26
lines changed

2 files changed

+50
-26
lines changed

base/sort.jl

+41-20
Original file line numberDiff line numberDiff line change
@@ -1475,21 +1475,15 @@ InitialOptimizations(next) = SubArrayOptimization(
14751475
Small{10}(
14761476
IEEEFloatOptimization(
14771477
next)))))
1478-
"""
1479-
DEFAULT_STABLE
14801478

1481-
The default sorting algorithm.
1482-
1483-
This algorithm is guaranteed to be stable (i.e. it will not reorder elements that compare
1484-
equal). It makes an effort to be fast for most inputs.
1485-
1486-
The algorithms used by `DEFAULT_STABLE` are an implementation detail. See extended help
1487-
for the current dispatch system.
1479+
"""
1480+
struct DefaultStable <: Algorithm end
14881481
1489-
# Extended Help
1482+
`DefaultStable` is an algorithm which indicates that a fast, general purpose sorting
1483+
algorithm should be used, but does not specify exactly which algorithm.
14901484
1491-
`DEFAULT_STABLE` is composed of two parts: the [`InitialOptimizations`](@ref) and a hybrid
1492-
of Radix, Insertion, Counting, Quick sorts.
1485+
Currently, it is composed of two parts: the [`InitialOptimizations`](@ref) and a hybrid of
1486+
Radix, Insertion, Counting, Quick sorts.
14931487
14941488
We begin with MissingOptimization because it has no runtime cost when it is not
14951489
triggered and can enable other optimizations to be applied later. For example,
@@ -1549,7 +1543,39 @@ stage.
15491543
Finally, if the input has length less than 80, we dispatch to [`InsertionSort`](@ref) and
15501544
otherwise we dispatch to [`ScratchQuickSort`](@ref).
15511545
"""
1552-
const DEFAULT_STABLE = InitialOptimizations(
1546+
struct DefaultStable <: Algorithm end
1547+
1548+
"""
1549+
DEFAULT_STABLE
1550+
1551+
The default sorting algorithm.
1552+
1553+
This algorithm is guaranteed to be stable (i.e. it will not reorder elements that compare
1554+
equal). It makes an effort to be fast for most inputs.
1555+
1556+
The algorithms used by `DEFAULT_STABLE` are an implementation detail. See the docstring
1557+
of `Base.Sort.DefaultStable` for the current dispatch system.
1558+
"""
1559+
const DEFAULT_STABLE = DefaultStable()
1560+
1561+
"""
1562+
DefaultUnstable <: Algorithm
1563+
1564+
Like [`DefaultStable`](@ref), but does not guarantee stability.
1565+
"""
1566+
struct DefaultUnstable <: Algorithm end
1567+
1568+
"""
1569+
DEFAULT_UNSTABLE
1570+
1571+
An efficient sorting algorithm which may or may not be stable.
1572+
1573+
The algorithms used by `DEFAULT_UNSTABLE` are an implementation detail. They are currently
1574+
the same as those used by [`DEFAULT_STABLE`](@ref), but this is subject to change in future.
1575+
"""
1576+
const DEFAULT_UNSTABLE = DefaultUnstable()
1577+
1578+
const _DEFAULT_ALGORITHMS_FOR_VECTORS = InitialOptimizations(
15531579
IsUIntMappable(
15541580
Small{40}(
15551581
CheckSorted(
@@ -1560,15 +1586,10 @@ const DEFAULT_STABLE = InitialOptimizations(
15601586
ScratchQuickSort())))))),
15611587
StableCheckSorted(
15621588
ScratchQuickSort())))
1563-
"""
1564-
DEFAULT_UNSTABLE
15651589

1566-
An efficient sorting algorithm.
1590+
_sort!(v::AbstractVector, ::Union{DefaultStable, DefaultUnstable}, o::Ordering, kw) =
1591+
_sort!(v, _DEFAULT_ALGORITHMS_FOR_VECTORS, o, kw)
15671592

1568-
The algorithms used by `DEFAULT_UNSTABLE` are an implementation detail. They are currently
1569-
the same as those used by [`DEFAULT_STABLE`](@ref), but this is subject to change in future.
1570-
"""
1571-
const DEFAULT_UNSTABLE = DEFAULT_STABLE
15721593
const SMALL_THRESHOLD = 20
15731594

15741595
function Base.show(io::IO, alg::Algorithm)

test/sorting.jl

+9-6
Original file line numberDiff line numberDiff line change
@@ -819,9 +819,9 @@ end
819819
let
820820
requires_uint_mappable = Union{Base.Sort.RadixSort, Base.Sort.ConsiderRadixSort,
821821
Base.Sort.CountingSort, Base.Sort.ConsiderCountingSort,
822-
typeof(Base.Sort.DEFAULT_STABLE.next.next.next.big.next.yes),
823-
typeof(Base.Sort.DEFAULT_STABLE.next.next.next.big.next.yes.big),
824-
typeof(Base.Sort.DEFAULT_STABLE.next.next.next.big.next.yes.big.next)}
822+
typeof(Base.Sort._DEFAULT_ALGORITHMS_FOR_VECTORS.next.next.next.big.next.yes),
823+
typeof(Base.Sort._DEFAULT_ALGORITHMS_FOR_VECTORS.next.next.next.big.next.yes.big),
824+
typeof(Base.Sort._DEFAULT_ALGORITHMS_FOR_VECTORS.next.next.next.big.next.yes.big.next)}
825825

826826
function test_alg(kw, alg, float=true)
827827
for order in [Base.Forward, Base.Reverse, Base.By(x -> x^2)]
@@ -861,15 +861,18 @@ end
861861
end
862862
end
863863

864-
test_alg_rec(Base.DEFAULT_STABLE)
864+
test_alg_rec(Base.Sort._DEFAULT_ALGORITHMS_FOR_VECTORS)
865865
end
866866
end
867867

868868
@testset "show(::Algorithm)" begin
869-
@test eval(Meta.parse(string(Base.DEFAULT_STABLE))) === Base.DEFAULT_STABLE
870-
lines = split(string(Base.DEFAULT_STABLE), '\n')
869+
@test eval(Meta.parse(string(Base.Sort._DEFAULT_ALGORITHMS_FOR_VECTORS))) === Base.Sort._DEFAULT_ALGORITHMS_FOR_VECTORS
870+
lines = split(string(Base.Sort._DEFAULT_ALGORITHMS_FOR_VECTORS), '\n')
871871
@test 10 < maximum(length, lines) < 100
872872
@test 1 < length(lines) < 30
873+
874+
@test eval(Meta.parse(string(Base.DEFAULT_STABLE))) === Base.DEFAULT_STABLE
875+
@test string(Base.DEFAULT_STABLE) == "Base.Sort.DefaultStable()"
873876
end
874877

875878
@testset "Extensibility" begin

0 commit comments

Comments
 (0)