Reversed Ranges

I find the concept of

for i in 1..n by -1 do {....}

ugly and unclear. I would much prefer to see

for i in n..1 do {...}
``1
but that is simply incorrect. But
```chapel
for i in -(1..n) do

is quite clear. But my crude routine

  inline operator -(r: range(?))
  {
    return r.low .. r.high by -r.stride;
   }

does not use new like the routines in ChapelRange.chpl.

Am I saling close to the wind or is that feasible?

I don't know the answer to your immediate question but another possibility is to add a method or function for ranges that reverses them, e.g. for i in reverse(1..n). Such a thing might be more findable in the documentation.

Thanks. That sounds smarter and more readable. What is the idea behind creating a new range and what do the arguments mean please?

Hello Damian,

Your operator - looks fine to me. What are your concerns about it or why is it not sufficient for you?

The new range() operator is not intended to be user-facing. However it surely comes handy for creating a range given all its properties, such as idxType, stridability, boundedness, bounds, stride, and alignment. Let me know your use cases and we can figure it out.

If you you want your operator - or proc reverse to be robust, let us know and we can work through a couple of considerations such as unbounded ranges (to avoid compilation errors) and the strides parameter of the result (for performance).

Vass

I'm not a fan of -(1..10), but didn't say so earlier since Michael's proposal seemed to cause Damian to back away from it. The main reason is that I don't think it's self-evident what it does, and relies on a very different interpretation of - than we normally have. A secondary reason is that today it results in promoting - across the range, so would be a breaking change post-2.0. For me, that combination of things suggests doing something different / clearer like Michael's suggestion.

-Brad

i am more than happy with reverse. I will scribble down what I think its code should be and people can tell me where it is suspect. I would assume that for my needs, an open range should be treated as a compilation error

Is this optimal?

  inline proc reverse(r: range(?))
  {
    return r.low .. r.high by -r.stride;
  }

Thanks

Re optimal: the strides parameter of the resulting range seems any instead of, ideally, negOne. Let me look into it.

Also keep in mind that r.low and r.high involve some computation when r.strides != strideKind.one. For example, reverse(1..5 by 2 align 2) gives 2..4 by -2.

Separately, I suggest you add an explicit check for clearer compiler error:

if r.bounds != boundKind.both then
  compilerError("only bounded ranges are allowed");

Hi Damian,

I mentioned this to Vass offline, but he's on vacation at the moment so
might not be checking his messages.

The improvements he's suggested here are definitely good things to
consider, and would be necessary to consider the feature stable. But
don't feel as though you have to add them in order to submit the feature
if you wanted to, even in your original form it could be useful to other
users. We would be happy to have that version in our code base as an
unstable feature, with some mention of the considerations outlined here,
e.g.,

/* This function is unstable because it needs explicit handling for 
strides other than <link to strideKind one>, <list of other things Vass 
> */
@unstable("reverse is unstable due to being new")
inline proc reverse(r: range(?))
   {
     return r.low .. r.high by -r.stride;
   }

Of course, if you need to or are interested in diving more into those
details yourself, please don't let me stop you from doing so! I just
don't want you to feel as though you have to go through the more
extensive robustness examination that we'd want to follow ourselves if
you're just trying to get something that works for a more limited case.

Thanks,
Lydia