# Why is there no isless(::Int64, ::UnitRange{Int64})?

**URL:** <https://discourse.julialang.org/t/why-is-there-no-isless-int64-unitrange-int64/112648>\
**Category:** General Usage\
**Tags:** range, unitrange\
**Created:** [April 7, 2024, 4:09pm UTC](https://discourse.julialang.org/t/why-is-there-no-isless-int64-unitrange-int64/112648 "2024-04-07T16:09:57Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![mnemnion](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mnemnion/32/206596_2.png) [@mnemnion](https://discourse.julialang.org/u/mnemnion)\
**Post date:** [April 7, 2024, 4:09pm UTC](https://discourse.julialang.org/t/why-is-there-no-isless-int64-unitrange-int64/112648/1 "2024-04-07T16:09:57Z")

</div>

It seems to me that all of these are unambiguous:

```julia
1 < 4:5 == true
2 ≤ 2:5 == true
3 ≤ 2:5 == true 
5 ≤ 2:5 == true
6 ≤ 2:5 == false
6 > 2:5 == true 
4 > 2:5 == false

```

That is, for any `Int`, we can derive an unambiguous and unsurprising answer for `<`, `≤`, `≥`, and `>` of a given `UnitRange{Int}`.

Is this just an oversight, or is there something about my take on what these comparisons should mean which doesn’t work?

---

<div class="post-metadata">

**Author:** ![screw\_dog](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/screw_dog/32/48119_2.png) [@screw\_dog](https://discourse.julialang.org/u/screw_dog)\
**Post date:** [April 7, 2024, 4:12pm UTC](https://discourse.julialang.org/t/why-is-there-no-isless-int64-unitrange-int64/112648/2 "2024-04-07T16:12:29Z")

</div>

What about `4 < 4:3`?

I think it’s generally better to not have default comparisons between scalars and collections

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [April 7, 2024, 5:15pm UTC](https://discourse.julialang.org/t/why-is-there-no-isless-int64-unitrange-int64/112648/3 "2024-04-07T17:15:09Z")

</div>

> [@mnemnion](#):
>
> `6 > 2:5 == true`

I think all of these are ambiguous. What does it even mean for a number to be ‘bigger’ than a collection? `2:5` has four members, how can it be smaller than a single number? If you compare the largest members, I suppose, but I don’t find that obvious.

What about `3 < 2:4`? Intuitively, to me, it’s neither smaller, bigger or equal.

---

<div class="post-metadata">

**Author:** ![greatpet](https://avatars.discourse-cdn.com/v4/letter/g/e495f1/32.png) [@greatpet](https://discourse.julialang.org/u/greatpet)\
**Post date:** [April 7, 2024, 5:46pm UTC](https://discourse.julialang.org/t/why-is-there-no-isless-int64-unitrange-int64/112648/4 "2024-04-07T17:46:08Z")

</div>

I’ve never seen people write down 1 \< [2, 3] in math classes. This kind of comparison neither exists as a common convention among programming languages nor in the common math notation.

---

<div class="post-metadata">

**Author:** ![mnemnion](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mnemnion/32/206596_2.png) [@mnemnion](https://discourse.julialang.org/u/mnemnion)\
**Post date:** [April 7, 2024, 6:08pm UTC](https://discourse.julialang.org/t/why-is-there-no-isless-int64-unitrange-int64/112648/5 "2024-04-07T18:08:15Z")

</div>

> [@DNF](#):
>
> I think all of these are ambiguous. What does it even mean for a number to be ‘bigger’ than a collection?

A range is a collection, yes, but it’s also an interval.

> [@DNF](#):
>
> What about `3 < 2:4`? Intuitively, to me, it’s neither smaller, bigger or equal.

`false`, clearly. `3` is not smaller than the interval `2:4`.

On the other hand, `3 ≤ 2:4` is correct.

`n == a:b` is false for all `n,a,b`, because a number and an interval aren’t ever equal.

> [@greatpet](#):
>
> This kind of comparison neither exists as a common convention among programming languages nor in the common math notation.

That’s weird, because [inequalities can be expressed as intervals](https://www.math.net/interval), so `[2,5]` is a way of representing `2 ≤ x ≤ 5`. So check this out:

```julia
julia> 2 ≤ 1 ≤ 5
false

julia> 2 ≤ 3 ≤ 5
true

julia> 2 ≤ 6 ≤ 5
false

```

So what’s wrong with:

```julia
1 < 2:5 == false
2 ≤ 2:5 == true

```

Exactly?

---

<div class="post-metadata">

**Author:** ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)\
**Post date:** [April 7, 2024, 6:15pm UTC](https://discourse.julialang.org/t/why-is-there-no-isless-int64-unitrange-int64/112648/6 "2024-04-07T18:15:35Z")

</div>

If we want to spin the thread of “what happens when we define this” further, what should `4 < 1:2:7` be? Clearly, 4 isn’t even in that range, so should it even be possible to compare these? What about floating point ranges?

For the vast majority of intervals, asking whether the entirety of the range is less/greater than a given value doesn’t really help with establishing an ordering between the two, since they are entirely different objects. You could use it as a shorthand for whether all of the numbers in the range are less/greater than the given number, but that feels much more like a `mapreduce` operation to me than trying to establish an order between integers and ranges of integers, so if it exists, should have a different name than `<`.

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [April 7, 2024, 6:15pm UTC](https://discourse.julialang.org/t/why-is-there-no-isless-int64-unitrange-int64/112648/7 "2024-04-07T18:15:40Z")

</div>

> [@mnemnion](#):
>
> `false`, clearly. `3` is not smaller than the interval `2:4`.

If it isn’t smaller, and it isn’t bigger, I guess `3 == 2:4` must be `true`, then?

IMO, if I write `3 < (2:4)`, I’ve made a mistake, and the desired result is an error. Otherwise, I would be _very_ disappointed.

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [April 7, 2024, 6:29pm UTC](https://discourse.julialang.org/t/why-is-there-no-isless-int64-unitrange-int64/112648/8 "2024-04-07T18:29:33Z")

</div>

> [@mnemnion](#):
>
> A range is a collection, yes, but it’s also an interval.

I missed this. I disagree that it’s an interval, it’s purely a discrete collection. If it were an interval then `2.5 in (1:5)` should be true.

---

<div class="post-metadata">

**Author:** ![mnemnion](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mnemnion/32/206596_2.png) [@mnemnion](https://discourse.julialang.org/u/mnemnion)\
**Post date:** [April 7, 2024, 6:35pm UTC](https://discourse.julialang.org/t/why-is-there-no-isless-int64-unitrange-int64/112648/9 "2024-04-07T18:35:09Z")

</div>

> [@DNF](#):
>
> If it isn’t smaller, and it isn’t bigger, I guess `3 == 2:4` must be `true`, then?

Nope! The set of scalars and intervals has a [strict partial order](https://en.wikipedia.org/wiki/Preorder#Strict_partial_order_induced_by_a_preorder), where equality is replaced with an equivalence relation, conventionally denoted `~`. The equivalence relation is `∈`.

So, in pursuit of notational orthodoxy, we might want to define `<` and `≲` where:

```julia
≲(i::Integer, r::UnitRange{<:Integer}) = i < r || i ∈ r

```

But I wouldn’t call it an outright abuse of notation to spell that `≤`, this is a programming language, not a chalkboard. It would be weird if `<` gave an answer but `<=/≤` threw an error harassing you to type `\lesssim` instead.

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [April 7, 2024, 6:35pm UTC](https://discourse.julialang.org/t/why-is-there-no-isless-int64-unitrange-int64/112648/10 "2024-04-07T18:35:17Z")

</div>

> [@mnemnion](#):
>
> `2 ≤ 2:5 == true`

So, then we would have

```julia
2 < 2:5 == false
2 == 2:5 == false
2 ≤ 2:5 == true 

```

?

---

<div class="post-metadata">

**Author:** ![mnemnion](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mnemnion/32/206596_2.png) [@mnemnion](https://discourse.julialang.org/u/mnemnion)\
**Post date:** [April 7, 2024, 6:38pm UTC](https://discourse.julialang.org/t/why-is-there-no-isless-int64-unitrange-int64/112648/11 "2024-04-07T18:38:49Z")

</div>

> [@DNF](#):
>
> I missed this. I disagree that it’s an interval, it’s purely a discrete collection. If it were an interval then `2.5 in (1:5)` should be true.

It’s an interval in the Integers, intervals of discrete sets are a valid concept. I agree that `2.5 ∈ 1:5` should be `false`, but don’t see the relevance to the question at hand.

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [April 7, 2024, 6:42pm UTC](https://discourse.julialang.org/t/why-is-there-no-isless-int64-unitrange-int64/112648/12 "2024-04-07T18:42:33Z")

</div>

`[1,2,3]` is not an interval and neither is `1:3`.

> [@mnemnion](#):
>
> I agree that `2.5 ∈ 1:5` should be `false`, but don’t see the relevance to the question at hand.

You equated greater/smaller comparison to a membership test in an interval a few posts up.

If `1 <= 2.5 <= 5` is true, then `2.5 ∈ 1:5` should also be.

---

<div class="post-metadata">

**Author:** ![mnemnion](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mnemnion/32/206596_2.png) [@mnemnion](https://discourse.julialang.org/u/mnemnion)\
**Post date:** [April 7, 2024, 6:46pm UTC](https://discourse.julialang.org/t/why-is-there-no-isless-int64-unitrange-int64/112648/13 "2024-04-07T18:46:20Z")

</div>

> [@DNF](#):
>
> So, then we would have
> 
> ```julia
> 2 < 2:5 == false
> 2 == 2:5 == false
> 2 ≤ 2:5 == true 
> 
> ```
> 
> ?

Yes. Not all orderings are total. What we would have is:

```julia
i < a:b → ¬(i ∈ a:b) ∧ ¬(i > a:b)
i ≤ a:b → i < a:b ∨ ∈ a:b
∀i,a,b ∈ ℤ, i ≠ a:b

```

Seems reasonable to me.

---

<div class="post-metadata">

**Author:** ![mnemnion](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mnemnion/32/206596_2.png) [@mnemnion](https://discourse.julialang.org/u/mnemnion)\
**Post date:** [April 7, 2024, 6:51pm UTC](https://discourse.julialang.org/t/why-is-there-no-isless-int64-unitrange-int64/112648/14 "2024-04-07T18:51:17Z")

</div>

> [@DNF](#):
>
> `[1,2,3]` is not an interval and neither is `1:3`.

Ok, call 1:3 “the set of integers in the interval [1,3]”. We’ll call that range.

So obviously, `2.5 ∈ 1:3` is `false` and `2 ∈ 1:3` is `true`. Nothing else changes.

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [April 7, 2024, 6:57pm UTC](https://discourse.julialang.org/t/why-is-there-no-isless-int64-unitrange-int64/112648/15 "2024-04-07T18:57:33Z")

</div>

`x <= y` means that either `x < y` _or_ `x == y`.

I only have a MSc in mathematics, so I am struggling to follow your arguments. The definitions you are proposing on common, everyday types are deeply puzzling and counterintuitive, and would not allow me to catch obvious bugs.

---

<div class="post-metadata">

**Author:** ![mnemnion](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mnemnion/32/206596_2.png) [@mnemnion](https://discourse.julialang.org/u/mnemnion)\
**Post date:** [April 7, 2024, 7:29pm UTC](https://discourse.julialang.org/t/why-is-there-no-isless-int64-unitrange-int64/112648/16 "2024-04-07T19:29:07Z")

</div>

> [@DNF](#):
>
> `x <= y` means that either `x < y` _or_ `x == y`.

Was the bit about `≾` really so unclear? Not every ordering is total, antisymmetry is not a requirement to have an ordering relation!

It gets its own notation in mathematics, because a) mathematicians do like to have a symbol for every possible variation of everything and b) sometimes one might deploy both sorts of orderings on a single blackboard, but this is a poor argument against overloading `≤` in this particular case. If someone were giving a lecture and had established that the set of interest has a strict partial order, and then wrote `κ ≤ φ` or whatever, would you correct them?

---

<div class="post-metadata">

**Author:** ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)\
**Post date:** [April 7, 2024, 7:30pm UTC](https://discourse.julialang.org/t/why-is-there-no-isless-int64-unitrange-int64/112648/17 "2024-04-07T19:30:51Z")

</div>

Why not just define your own operator? The following uses `\lessdot`.

```julia
julia> ⋖(x::Number, y::UnitRange) = x < first(y) && x < last(y)
⋖ (generic function with 1 method)

julia> 0 ⋖ 1:5
true

```

---

<div class="post-metadata">

**Author:** ![dylanxyz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dylanxyz/32/36646_2.png) [@dylanxyz](https://discourse.julialang.org/u/dylanxyz)\
**Post date:** [April 7, 2024, 7:40pm UTC](https://discourse.julialang.org/t/why-is-there-no-isless-int64-unitrange-int64/112648/18 "2024-04-07T19:40:20Z")

</div>

Or maybe:

```julia
julia> struct Interval{T <: Number}
           a::T
           b::T
       end

julia> a..b = Interval(promote(a, b)...)
.. (generic function with 1 method)

julia> Base.isless(n::Number, it::Interval) = n < it.a && n < it.b

julia> 2 < 3..4
true

julia> 2 < 2..4
false

```

---

<div class="post-metadata">

**Author:** ![mnemnion](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mnemnion/32/206596_2.png) [@mnemnion](https://discourse.julialang.org/u/mnemnion)\
**Post date:** [April 7, 2024, 7:42pm UTC](https://discourse.julialang.org/t/why-is-there-no-isless-int64-unitrange-int64/112648/19 "2024-04-07T19:42:00Z")

</div>

> [@mkitti](#):
>
> Why not just define your own operator? The following uses `\lessdot`.

I’ve no objection, and would probably use `≾` just out of orthodoxy. But here’s the documentation from `isless`, it’s expected to uphold the following two relations:

> If isless(x, y) is defined, then so is isless(y, x) and isequal(x, y), and exactly one of those three yields true.

```julia
3 < 4:5 == true 
3 > 4:5 == false 
3 == 4:5 == false

```

> The relation defined by isless is transitive, i.e., isless(x, y) && isless(y, z) implies isless(x, z).

```julia
2 < 3:5 == true 
3:5 < 6 == true
2 < 6 == true

```

So no problem there. All that the documentation says about `≤` is this:

> Less-than-or-equals comparison operator. Falls back to (x \< y) | (x == y).

What it does _not_ say is that antisymmetry and total ordering has to hold for this operator! It could! It just says “in the event that `≤` isn’t defined, it will be treated as though the set of the type is totally ordered”.

So it seems like a reasonable candidate for `≤/<=`, which are both much less ponderous to enter than `\lesssim` or `\lessdot`, and would allow for easier generic code.

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [April 7, 2024, 7:54pm UTC](https://discourse.julialang.org/t/why-is-there-no-isless-int64-unitrange-int64/112648/20 "2024-04-07T19:54:01Z")

</div>

> [@dylanxyz](#):
>
> Or maybe:
> 
> `julia> struct Interval{T <: Number}`

For example, Intervals.jl does this for you.

[Next page](https://discourse.julialang.org/t/why-is-there-no-isless-int64-unitrange-int64/112648.md?page=2)
