JuliaLang / julia

The Julia Programming Language
https://julialang.org/
MIT License
45.74k stars 5.49k forks source link

The result of an empty intersection of ranges is confusing #40331

Open gbaraldi opened 3 years ago

gbaraldi commented 3 years ago

If you call intersectbetween two ranges and the result is empty it returns an empty range of the form 5:4 as in like

julia> a = 1:3
1:3

julia> b = 5:6
5:6

julia> intersect(a,b)
5:4

That can be confusing since you might interpret 5:4 as 5:-1:4 Using Float ranges gives a different result though

julia> a = 30:0.5:42
30.0:0.5:42.0

julia> b = 15:0.5:25
15.0:0.5:25.0

julia> intersect(a,b)
Float64[]
sostock commented 3 years ago

Maybe we could print empty ranges differently, adding a hint like the following:

julia> 5:4
5:4 (empty UnitRange{Int})
gbaraldi commented 3 years ago

There should be a better way to show an empty range then 5:4 or 6.0:5.0 since one, it's not unique and two it's confusing. And using array notation might be even worse.

vtjnash commented 3 years ago

Commonly, we summarize by printing the length of an array. Might we useful always?

julia> codeunits("a")
1-element Base.CodeUnits{UInt8, String}:
 0x61

julia> codeunits("")
0-element Base.CodeUnits{UInt8, String}

julia> ans isa AbstractVector
true
lazarusA commented 1 year ago

this issue should definitely be addressed somehow. For all things (sets) empty probably the best should be to print

julia > intersect(a,b)
 ∅

or similar to [by @sostock ]

julia > intersect(a,b)
empty UnitRange{Int}

without any ranges left in the printing, which are really confusing.

sostock commented 1 year ago

For ranges, the start/stop values sometimes carry meaning even for empty ranges. From the searchsorted docstring:

julia> searchsorted([1, 2, 4, 5, 5, 7], 3) # no match, insert in the middle
3:2

julia> searchsorted([1, 2, 4, 5, 5, 7], 9) # no match, insert at end
7:6

Here, not printing the values for empty ranges would hide where the number would be inserted. Therefore, I think that the start/stop values should always be printed for ranges, even when they are empty.

lazarusA commented 1 year ago

hide where the number would be inserted.

the problem is that the output looks like the actual value output, when in practice one needs the emptyness of that operation. If you want to keep that information for whatever reason, then it should appear after the actual value output, e.g.,

julia> searchsorted([1, 2, 4, 5, 5, 7], 3)
∅ (empty 3:2)
mcabbott commented 1 year ago

To try out always printing the length, as other arrays do:

julia> function Base.show(io::IO, ::MIME"text/plain", r::AbstractRange)
         summary(io, r); print(io, ":\n "); show(io, r)
       end

julia> intersect(1:3, 5:6)
0-element UnitRange{Int64}:
 5:4

julia> 1:2:3
2-element StepRange{Int64, Int64}:
 1:2:3

julia> LinRange(1,2,3)  # unchanged
3-element LinRange{Float64, Int64}:
 1.0, 1.5, 2.0

julia> range(1,2,3)  # quite long
3-element StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64}:
 1.0:0.5:2.0
oscardssmith commented 5 days ago

Triage thinks the first answer proposed was the right one.

5:4 (empty UnitRange{Int})
StefanKarpinski commented 4 days ago

Maybe just 5:4 (empty range) since most don't care about the type?