Hi Damian β
For a pattern like yours, I might be inclined to write it as:
var (rL,rH) = (rows.low, rows.high);
for c in columns do
{
....
rL += 1;
... rL..rH ...
}
for a few reasons:
- makes the increment of the low bound a bit more explicit / in the reader's face
- if the thing you're doing with the
rL..rH
range is looping over it, I suspect you may get a simpler for loop out of it and avoid creating a new range object (which is what the creation and modification of rL
will do)
Or, if columns.size == rows.size, you might do:
for (c,rL) in zip(columns, rows) {
... rL..rH ...
}
to more directly tie the value of rL
to the loop header rather than the body. Or, I suppose, even if they're different sizes, you could do:
for (c,rL) in zip(columns, rows.low..) {
... rL..rH ...
}
OTOH, if you're not using the shrinking row range within the loop body to drive an inner loop and are using the row sub-range expression multiple times within the routine, calling your helper routine may be preferable in terms of creating a new range once and using it multiple times.
To your original "What is the overhead?" question, in general, creating a new range is a matter of setting up a small struct with a few integers in it, and using it is a matter of plucking those values out of the range. Using a helper routine to create the range ought to result in fairly minimal overhead, and you may be able to reduce it further using inline proc
. But I don't have enough experiment with benchmarking range creation idioms to be able to say very definitively which will work best.
The thing that makes me suggest using the rL..rH
range literal if you're writing a loop is that the compiler transforms loops of the form:
for i in lo..hi do
into something resembling a more straightforward C loop without introducing a range object.
In most heavy-duty computations, I'd like to think that the differences between all of the above, including yours, are a wash. And if that were not the case, it may just suggest we have more optimization work to do here.
-Brad