New Issue: Range.hasAlignment() proposal

19717, "vasslitvinov", "Range.hasAlignment() proposal", "2022-04-28T00:30:33Z"

This issue is a fork from Range property query names · Issue #17131 · chapel-lang/chapel · GitHub to discuss today's range.aligned.

Background: #17131 requests better names for range.stridable and range.aligned. While working on the latter, I realized that the underlying terminology and behavoir will benefit from some cleanup.

For background on alignment, see the spec. To summarize:

  • the range (.. by 2 align 0) defines the sequence ..., -2, 0, 2, ...
  • the range (.. by 2 align 1) defines the sequence ..., -1, 1, 3, ...
  • (.. by 2 align 2) is the same as (.. by 2 align 0)
  • the sequence of indices for the range (.. by 2) is undefined because we do not know which of the above it is

The proposal

  • Terminology:
    A range either has alignment or doesn't.
    Alternatively - or colloquially: a range either is aligned or is not.
    If a range has alignment, we can say colloquially its alignment is defined.
    If a range does not have alignment, it is illegal to query is alignment;
    its "represented sequence" is undefined.

  • Methods:
    one of: r.hasAlignment() or r.isAligned()
    the latter is easier to say and write, the former is crisper terminology
    r.alignment reports the alignment if it is defined, an error otherwise
    r.alignmentString returns the alignment or the string "undefined"
    this functionality comes handy for examining ranges ex. for debugging

  • Behavior:
    Unstridable ranges always have the alignment of 0.
    The alignment of r by S, where r is unstridable and S > 0, is:
    r.low if defined, else r.high if defined, else not defined.
    If S < 0 then it r.high is tried first.
    .. by S does not have alignment.

  • Opionally:
    Allow hasAlignment() to be a param.
    Rationale: if "aligned" ranges are the common case among stridable ranges,
    we do not need to carry the boolean at runtime unless necessary.

What's the big deal?

Currently the spec defines that a range's alignment may be ambiguous and that the range can be ambiguously aligned. These two properties differ for unstridable ranges, which have ambiguous alignment yet are not ambiguously aligned.

If we were to retain this terminology, we would need two different "has alignment" queries. This proposal is to replace two properties with one.

Why did we introduce these almost-the-same properties?

My understanding is that this was our way to ensure that .. by S and similar did not have alignment. This proposal is to achieve this goal differently, i.e., by stating that directly, in order to have just one property.

This proposal includes the definition of the alignment using the last index when the first index is not available. For example, ..5 by 2 has the alignment of 5 and 1.. by -2 has the alignment of 1, whereas currently these ranges' alignments are undefined. Rationale: if I can infer the alignment from the index where I start, I may as well infer it from the index where I stop, when there is no starting point. This part of the proposal is independent of the other pieces.

Currently ranges define the method r.aligned, with questionable semantics. The method name leaves it unclear whether it returns a boolean property or an aligned version of r, as discussed on #17131. isAligned() or hasAlignment() make it clear. There is no support for updating this property other than by reassigning the entire range, which is consistent with our view or ranges as an immutable datatype. For example, we cannot update just the stride or just one of the bounds.

Currently ranges define the method r.alignment which is invocable on all ranges, although its behavior is (supposed to be) undefined for non-aligned ranges. This proposal makes it an error instead of undefined behavior in those cases.

This proposal introduces r.alignmentString that is always invocable. This is merely a convenience. Rationale: a few tests currently print out r.alignment "for your information". It would be a hassle for those tests to guard such printout with a conditional statement, which would be necessary once r.alignment starts generating an error in some cases.