# 'Negative' UnitRange in Julia?

**URL:** <https://discourse.julialang.org/t/negative-unitrange-in-julia/72864>\
**Category:** General Usage\
**Created:** [December 9, 2021, 10:21pm UTC](https://discourse.julialang.org/t/negative-unitrange-in-julia/72864 "2021-12-09T22:21:42Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![DorianT](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/doriant/32/24897_2.png) [@DorianT](https://discourse.julialang.org/u/DorianT)\
**Post date:** [December 9, 2021, 10:21pm UTC](https://discourse.julialang.org/t/negative-unitrange-in-julia/72864/1 "2021-12-09T22:21:42Z")

</div>

Today I came across some behaviour regarding UnitRanges that I did not quiet understand. I was hoping to find some enlightenment here 👼

The issues boils down to this behavior, below is some more context:

```julia
julia> 4:8
4:8

julia> 8:4
8:7

julia> 8:4 |> typeof
UnitRange{Int64}

```

`@code_lowered` and `@code_typed` also produced similar output for both. However:

```julia
j = 1:2:20 |> collect

julia> j[4:8]
5-element Vector{Int64}:
  7
  9
 11
 13
 15

julia> j[8:4]
Int64[]

```

But most confusing to me is that:

```julia
julia> j[8:-1:4]
5-element Vector{Int64}:
 15
 13
 11
  9
  7

```

Produces just the behavior I would expect?

In R this behavior just works fine, I don’t know if it is discouraged in Julia for some reason?

```julia
r = seq(1,20,2)
r[8:4]
[1] 15 13 11 9 7

```

PS: I came across this behaviour trying to index a matrix using 2 ranges to get a sub matrix and sometimes the ranges can be ‘negative’ (i.e. starting with the larger number first).

My questions are: Why is Julia currently behaving like this? I especially don’t understand the output of negative ranges always being `start:start-1`. Is there a better way to do this in base or is there a package that can be used to enable this kind of behaviour?

Edit: Typos

---

<div class="post-metadata">

**Author:** ![stillyslalom](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stillyslalom/32/45687_2.png) [@stillyslalom](https://discourse.julialang.org/u/stillyslalom)\
**Post date:** [December 9, 2021, 10:48pm UTC](https://discourse.julialang.org/t/negative-unitrange-in-julia/72864/2 "2021-12-09T22:48:02Z")

</div>

`(a::Int):(b::Int)` creates a `UnitRange`, which has a step of `+1` by definition:

```julia
help?> UnitRange
search: UnitRange AbstractUnitRange

  UnitRange{T<:Real}

  A range parameterized by a start and stop of type T, filled with elements
  spaced by 1 from start until stop is exceeded. The syntax a:b with a and b
  both Integers creates a UnitRange.

```

The negative range endpoint coercion allows the length of a `UnitRange` to always be equal to `stop - start + 1`, which avoids an unnecessary branch in subsequent calculations of `length`. If you want to create `StepRange`s with a unit step of the proper sign, you could do something like this:

```julia
julia> ..(a, b) = a:sign(b - a):b
.. (generic function with 1 method)

julia> 4..8
4:1:8

julia> 8..4
8:-1:4

```

\*\*edit: this is more robust (works for `a == b`):

```julia
julia> ..(a, b) = a:sign(b - a + (a == b)):b
.. (generic function with 1 method)

julia> 2..2
2:1:2

```

---

<div class="post-metadata">

**Author:** ![DorianT](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/doriant/32/24897_2.png) [@DorianT](https://discourse.julialang.org/u/DorianT)\
**Post date:** [December 9, 2021, 11:11pm UTC](https://discourse.julialang.org/t/negative-unitrange-in-julia/72864/3 "2021-12-09T23:11:50Z")

</div>

> The negative range endpoint coercion allows the length of a `UnitRange` to always be equal to `stop - start + 1` , which avoids an unnecessary branch in subsequent calculations of `length` .

So this refers to the compiler having to do less work with the current implementation?

Thanks for the nice explanation though. Your proposed solution is great, I will implement it right away.

I am still a bit curious as to why for ranges `start:stop` with `start < stop` currently a range of `start:start-1` is returned? Is there a particular use case for this? Would an error not more desirable, because otherwise silently an empty collection is returned which may lead to unintended behaviour?

---

<div class="post-metadata">

**Author:** ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)\
**Post date:** [December 10, 2021, 1:27am UTC](https://discourse.julialang.org/t/negative-unitrange-in-julia/72864/4 "2021-12-10T01:27:59Z")

</div>

> [@DorianT](#):
>
> Is there a particular use case for this?

yes, so when you do a loop over ends points, you get the correct behavior (empty, 0-length, skip it) without manually worrying about which number is larger.

* * *

> [@DorianT](#):
>
> the compiler having to do less work with the current implementation?

Julia implemements short cuts (specialized methods) that make sense, for example:

 ![image](https://global.discourse-cdn.com/julialang/original/3X/c/3/c374a01897a69867d5725ae886d99e79ec52dc11.png)

even if the range is not “Unit” anymore, there’s still a shortcut.

---

<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:** [December 10, 2021, 2:33am UTC](https://discourse.julialang.org/t/negative-unitrange-in-julia/72864/5 "2021-12-10T02:33:35Z")

</div>

The more general way of creating a range is via `range`. There you can also specify `length` or `step`:

```julia
julia> r_length = range(start=3, stop=-6, length=10)
3.0:-1.0:-6.0

julia> typeof(r_length)
StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64}

julia> collect(r_length)
10-element Vector{Float64}:
  3.0
  2.0
  1.0
  0.0
 -1.0
 -2.0
 -3.0
 -4.0
 -5.0
 -6.0

julia> r_step = range(start=3, stop=-6, step=-1)
3:-1:-6

julia> typeof(r_step)
StepRange{Int64, Int64}

julia> collect(r_step)
10-element Vector{Int64}:
  3
  2
  1
  0
 -1
 -2
 -3
 -4
 -5
 -6

```

---

<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:** [December 10, 2021, 10:15am UTC](https://discourse.julialang.org/t/negative-unitrange-in-julia/72864/6 "2021-12-10T10:15:37Z")

</div>

There’s also the issue of type stability, which is so central in Julia (and in particular for a commonly used construct like `UnitRange`). The step length of `+1` is encoded in the type itself. If `stop<start` caused the step to become `-1`, it would no longer be a `UnitRange`, and when output types depend on values, you have a type instability.

BTW, in contrast to R, this is Matlab:

```matlab
>> 5:3
ans =
  1×0 empty double row vector

```

---

<div class="post-metadata">

**Author:** ![DorianT](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/doriant/32/24897_2.png) [@DorianT](https://discourse.julialang.org/u/DorianT)\
**Post date:** [December 10, 2021, 11:01am UTC](https://discourse.julialang.org/t/negative-unitrange-in-julia/72864/7 "2021-12-10T11:01:02Z")

</div>

Thanks for the further explanations! I also had a look at the issues and found [https://github.com/JuliaLang/julia/issues/40331](https://github.com/JuliaLang/julia/issues/40331), which probably helps others not get confused like I have 🙂
