Range Issues

Why are

range

and

range(stridable = true)

totally different types?

In fact, I cannot see how

1 .. 10 by 1

and

1 .. 10

are any different. Both have unit stride, i.e. a stride of 1. Why
one if considered stridable and the other not is totally beyond me.

This is important when you want to specify a parameter to a routine which
can be either a stridable or non-stridable range. How is this done now?
As far as I can see, it cannot be done. For example

proc test(r : range)

will not accept

test(1 .. 10 by 1)

If I change the type of ‘r’ such that it reads as

r : range(stridable = true)

the compiler is happy, but then my routine test will then not accept

test(1..10)

What am I missing or has type strictness gone overboard?

Regards - Damian

Pacific Engineering Systems International, 277-279 Broadway, Glebe NSW 2037
Ph:+61-2-8571-0847 … Fx:+61-2-9692-9623 | unsolicited email not wanted here
Views & opinions here are mine and not those of any past or present employer

Hi Damian -

To write a procedure accepting ranges of any type you can use

proc test(r : range(?)) { }

This is a frequently encountered issue for ranges so I think it should be added as an example to Ranges — Chapel Documentation 1.24 and Ranges — Chapel Documentation 1.24 .

The (?) syntax for a formal argument type is described here: Generics — Chapel Documentation 1.24 and is in particular needed for generic types with defaults (and range is one such type).

1 Like

Hi Damian —

Though these ranges happen to have the same value, a range(stridable=true) can hold 1..10 or 1..10 by 2 where a range(stridable=false) can only hold 1..10, not 1..10 by 2. range is a convenience alias for the range(stridable=false) case, which we believe to be the important/common case to optimize for.

The reason for this distinction in the type is one of efficiency: a non-stridable (bounded) range can be represented by two integers representing the low and high bounds; whereas a stridable range has to store four integers, representing the bounds, stride, and alignment.

But more important than the space overhead is the code generated for the different types. Stridable ranges result in for-loops that step through their integers using the stride integer which isn’t generally known at compile-time. Moreover, since stridable ranges support positive or negative strides, and negative strides result in running through ranges backwards, the generated loops also often have to be general w.r.t. iteration order. In contrast, non-stridable ranges step through their integers by 1 in low->high order, resulting in code that is simpler and typically easier for a back-end compiler to reason about and optimize.

This answers the bit of your mail about why we distinguish between these cases in the range’s type. I think Michael addressed the part about how to indicate a generic range type, but let us know if you have follow-up questions.

-Brad

Thanks for the reply.

So it seems that I treat the range as a generic type. That works. Thanks.

But are not there serious restrictions on a ‘proc’ with generic types?

Stay safe - Damian

Pacific Engineering Systems International, 277-279 Broadway, Glebe NSW 2037
Ph:+61-2-8571-0847 … Fx:+61-2-9692-9623 | unsolicited email not wanted here
Views & opinions here are mine and not those of any past or present employer

There are some restrictions, but I don’t know if I’d call them serious ones… A procedure taking a generic type can’t be exported outside of Chapel because we resolve the generic instantiations by looking at the callsites (so for an exported procedure, we can’t guess what the calls will be). But I don’t think we support exporting routines that take ranges or other complex types currently anyway, so that probably doesn’t apply. I can’t think of other significant restrictions offhand, but maybe am just not thinking of something that you are…

You could also create stridable and non-stridable overloads of the routine, which would make them non-generic (and could implement the non-stridable version by converting it to a stridable range and calling the stridable version to avoid the code duplication; though you’d also lose the performance benefits afforded to non-stridable ranges…).

-Brad