When I sent this originally as part of an early email to discourse, Chapel chopped it off. Odd.
Anyway, .....
There seem to be some methods which return a new range for which the name is a verb
expand(d : idxType)
translate(d : idxType)
There are also two other methods that return a related range
interior(d : idxType)
exterior(d : idxType)
but their names are nouns.
The mix of nouns and verbs for methods which both return ranges seems out of place and it would be good to know the logic behind the choice of a mix. Then again, I cannot see for what I would use the 'interior' or the 'exterior' method so maybe they are useless.
I ask this because I want to add a method for a range and would like to follow the existing semantics as long as they make sense (and maybe even if they do not).
Anyway, I need a range method which returns a new range which is a subset of the original but where only one end is affected. A haircut for the head of the range OR the equivalent for the tail, not both as yielded by expand with a negative argument.
If I choose a verb, say "cut", "trim", "snip", "crop", "scrape", "pare" "lop", "prune", "shrink" or "shave" and I follow Python to chose a positive integer be associated with the lower bound and negative one with the upper bound, then given a range
const r = 1 .. n;
I want to
assert(r.shave(+1) == 2 .. n);
// AND
assert(r.shave(-1) == 1 .. n - 1);
Note that I am only interested in subsets of the original range, not a superset. The absolute value of the argument will normally be 1 or 2. Now others may have different needs so the generalization of what I am doing will need extra thought.
I wrote:
proc range.shave(i : integral) return if this.stridable
then
(
if i > 0:i.type then
this.low + this.stride * i:this.idxType .. this.high
by this.stride
else
this.low .. this.high + this.stride * i:this.idxType
by this.stride
)
else
(
if i > 0:i.type then
this.low + i:this.idxType .. this.high
else
this.low .. this.high + i:this.idxType
);
I do not understand how this works because it returns both stridable and non-stridable ranges (whatever stridable really means - see below) about which the compiler complains in other scenarios.
So, how do I write this properly and how optimal is this? Certainly the first part of the 'if' is done at compile time because 'stridable' is a param. What overhead does it have? I want minimal overhead. The only other examples I can find are in ChapelRange.chpl. These are internal methods of a range and work with internal variables of the range and often then play with the Chapel 'new' operator. So they are not much use to help me write my own method outside of this file.
What does the current concept of stridable mean? Also, why is a range with an implied stride (i.e. of 1) not stridable when it clearly is, i.e. with a stride of 1? On first reading, I thought the 'stridable' method meant
! (the range has a (known at compile time) unit-stride)
but that is not the case because ranges
const r0 = 1 .. 10;
const r1 = 1 .. 10 by 1;
are different even that the compiler should be able to treat them identically, i.e. the stride of '1' in the case of 'r1' is known at compile time.
It almost looks like it means
! (the range has a implicit (and known at compile time) unit-stride)
Is this correct? Either way, whatever it means, the method/concept needs a new name with at least a semblance of semantic correctness. As it stands it is confusing because every range is stridable, i.e. can be strode, irrespective of the return value of the Chapel 'stridable' method.
Why does the documentation say stridable is a 'proc' when in ChapelRange.chpl is is clearn a param?