<!DOCTYPE html><html><head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  </head>
  <body>
    <font size="4" face="monospace">Sorry for the not-good news, but I'm
      not too surprised.  Computational domains like "32 bit integers"
      seem like they should have a lot in common with algebraic
      structures like groups and rings, but when you start poking at
      them, the compromises we make to fit them into hardware registers
      start to bite.  (And let's not get started on floating point...) 
      Lots of research into numeric towers in various languages, or
      capturing fundamental properties in type classes like Haskell's
      `Eq` and `Ord`, offers plenty of compromise to go with its
      promise.  <br>
      <br>
      I think a big part of what you are running into is that you've
      started with a _concept_ (a deceptively simple one, at that),
      rather than _requirements_.  And it is the open-endedness of this
      concept (discrete vs continuous, bounded vs half-open, including
      endpoints or not, etc) that resists abstraction.  Plus, without
      clear requirements, you will be subject to an endless barrage of
      "what about my pet use case" (e.g., "what about the numbers zero
      to ten, advancing by two").  Meanwhile, domain-specific libraries
      such as java.time will invent their own domain-specific answers,
      like Interval.  <br>
      <br>
      Rather than starting from the algebraic properties, perhaps start
      from the other end: what are the use cases where the lack of a
      range abstraction is problematic.  I get that <br>
      <br>
          for (int i=0; i<100; i++) { ... }<br>
      <br>
      is uglier and less abstract than <br>
      <br>
          for (int i : Range.of(0, 100)) { ... }<br>
      <br>
      but I also don't sense people beating down the doors for that
      (even if the language had range literals, like `0..<100`).  <br>
      <br>
      Where I do see people having trouble is that many range
      computations are error prone.  For example, `String::indexOf`
      returns the starting index of a match; if you want to actually
      iterate over the characters of such a match, you have to do
      something like<br>
      <br>
          for (int j=index; j<index+target.length(); j++)<br>
      <br>
      and you are at risk for fencepost errors when recreating the
      range.  Whereas an indexOf method (under a more suitable name)
      that returned a range, would be more amenable to downstream
      processing.  Similarly, I see errors in API usage because
      sometimes we specify range by (start, end) and sometimes by
      (start, length), and since both are ints, we get no type checking
      when you pass the wrong kinds of ints to such a method.  <br>
      <br>
      But, the mere existence of a Range type would do little to help
      String, Arrays, and other range-happy APIs, because we would have
      to update them to include new overloads that dispense and consume
      ranges.  So that's a big project.  <br>
      <br>
      Still, I think investigating use cases involving libraries that
      work intensively with ranges like this would likely yield useful
      information for what a Range type would want to provide.<br>
      <br>
      HTH,<br>
      -Brian<br>
      <br>
      <br>
      <br>
      <br>
      <br>
    </font><br>
    <div class="moz-cite-prefix">On 9/26/2024 9:07 AM, Olexandr Rotan
      wrote:<br>
    </div>
    <blockquote type="cite" cite="mid:CAL5bRt9zu_WtHUi-0J2L5LThpWfCaGWCrd5cxLHNkJJ52uHHxA@mail.gmail.com">
      
      <div dir="ltr">Researching the of deriving some iterable
        representations from ranges, and I am not here with the good
        news.<br>
        <br>
        Unlike range algebra and boolean operations, which generalize
        extremely well, iterability of ranges... Well, it's safe to say
        it doesn't generalize at all. Analyzing key features people
        expect iterable ranges to have, I ended up concluding there are
        basically two groups / two use cases for them. First is plain
        and simple, arguably the most popular one: iterating over a
        range of integer numbers, i.e. `for (i : Range.of(1, 10))`.
        Another use case is for more complex iterations over ranges of
        reference types, most commonly dates/time.<br>
        <br>
        There are two groups of values by their nature: discrete and
        continuous. Most of the types belong to the second group, as
        there is no direct increment AND decrement for them (we will
        omit hardware limitations for simplicity), such as floating
        point values. What is the increment of 1,3? 1.31 or
        1.30000000001, or maybe something even more unreadable? On the
        other hand, the increment of LocalDate in context of range
        iteration that represents today is rather obvious - it is
        tomorrow.
        <div><br>
        </div>
        <div>There is a pretty limited number of discrete types in jdk.
          Dates, whole numbers and basically that's it. The discrete
          types that are not present in jdk can be really various. For
          example, users can define a comparable type "F1Team" and
          compare them based on their position in the last race. There,
          increment would most likely be the next team in rating. There
          are many domain-specific cases like this.<br>
          <br>
          This is where the problem comes from. If the user would always
          have to pass a comparator to create a range, it would be
          consistent to make the user define increment/decrement as
          well. But we don't want users to pass a comparator if the type
          is already comparable. Similarly, we don't want users to
          define increment/decrement if there is already one in the
          language! I think defining increments for dates (say
          LocalDate.plusDays(1)) would be acceptable,
          even defining increments for floats in context of ranges might
          be acceptable, but making people define increments for
          integers is, in my opinion, completely not. Besides
          performance impact, this is a terrible user experience.</div>
        <div><br>
        </div>
        <div>There are a few solutions to this:<br>
          1) Define ton of overrides for factory methods and specialized
          types for this (uhh, sounds awful)</div>
        <div>2) Introduce new interface, say Discrete<T>, that
          defines T increment() (and possible T decrement()) methods.
          From now on, there are 2 branches:<br>
          2.1) Leave things as is, allow users to define incrementation
          logic for their types, but don't touch integers and other
          built-ins.I see this option as extremely inconsistent and not
          solving the main issue, which is iterability of integers.</div>
        <div>2.2) Retrofit (scary) existing types to implement this
          interface. This should not have any compatibility nor security
          implications, but still sneaking into java.lang every time we
          need some new API to be more user-friendly is obviously not a
          way to go. This basically comes down to a question about how
          deep we want to integrate ranges into language, and is range 
          generalization even worth the invasion into the core of
          language (imo yes).</div>
        <div>3) Leave things as they are, just let users derive
          iterables using something like
          range.asIterableWithStep(IncremetStartegy increment). I think
          this would make an API too narrow as no one will use it for
          routine tasks the same way people do in Rust, Kotlin and other
          languages.<br>
          <br>
          I would love to hear community opinion on this matter. Which
          option is the most preferable, maybe some compromise between a
          few of them, or maybe there is a better way to go that I
          didn't mention here?<br>
          <br>
          Best regards</div>
      </div>
      <br>
      <div class="gmail_quote">
        <div dir="ltr" class="gmail_attr">On Tue, Sep 24, 2024 at
          5:11 PM Alan Snyder <<a href="mailto:javalists@cbfiddle.com" target="_blank" moz-do-not-send="true" class="moz-txt-link-freetext">javalists@cbfiddle.com</a>>
          wrote:<br>
        </div>
        <blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
          <div><span style="color:rgb(0,0,0)">I have another example: I
              have a datatype that represents a region of an audio
              track, for example, one tune in a medley of tunes. I allow
              the region to</span>
            <div style="color:rgb(0,0,0)">specify both a start and end
              time, but the end time is optional (and mostly not used).
              When the end time is not specified, the region ends at the
              start of the next region, or at</div>
            <div style="color:rgb(0,0,0)">the end of the track if there
              is no next region. The latter case is useful because the
              exact track length may not be known. The optionality of
              the end time</div>
            <div style="color:rgb(0,0,0)">is not represented in the type
              system.</div>
            <div style="color:rgb(0,0,0)"><br>
            </div>
            <div style="color:rgb(0,0,0)">Having said that, I’m not sure
              that a general abstract interface would be useful for this
              example.<br id="m_-1709372893632724312m_3927220230334710857lineBreakAtBeginningOfMessage">
              <div><br>
                <blockquote type="cite">
                  <div>On Sep 24, 2024, at 2:13 AM, Olexandr Rotan <<a href="mailto:rotanolexandr842@gmail.com" target="_blank" moz-do-not-send="true" class="moz-txt-link-freetext">rotanolexandr842@gmail.com</a>>
                    wrote:</div>
                  <br>
                  <div>
                    <div dir="ltr">As part of the redesigning  process ,
                      I am researching whether or not there are use
                      cases that require asserting that the range is
                      exactly half-bounded. This is important because I
                      plan to switch to BoundedAtEnd/BoundedAtStart
                      sealed interfaces instead of flags and runtime
                      checks: Here is what I gathered for now.<br>
                      <br>
                      <ul>
                        <li><strong>Date/Time Handling (Historical or
                            Forecast Data)</strong>: When dealing with
                          events that started at a specific time but
                          have no known end (e.g., open-ended employment
                          contracts or ongoing subscriptions)</li>
                        <li><strong>Stream Processing (Real-time Event
                            Streams)</strong>: In real-time systems, you
                          might process data that has a start time but
                          no defined end, such as monitoring a live
                          video feed or logging system. The range is
                          bounded at the start and unbounded at the end
                          as more data will continuously arrive.</li>
                        <li><strong>Data Pagination (Fetch Until
                            Condition)</strong>: When implementing
                          pagination, sometimes you might want to fetch
                          items starting from a specific index up to an
                          unbounded limit (e.g., fetching all items
                          after a certain point until memory runs out or
                          a condition is met).</li>
                        <li><strong>Auditing and Monitoring</strong>: In
                          systems where audit trails or logging data
                          should capture all events after a certain
                          point (bounded start) with no foreseeable end
                          (unbounded end), such as monitoring changes to
                          records in a database starting from a fixed
                          timestamp.</li>
                        <li><strong>Scientific or Statistical Ranges</strong>:
                          When modeling physical systems or statistical
                          ranges, you might want to capture measurements
                          that begin at a known threshold but
                          theoretically have no upper or lower bound.
                          For example, recording temperature data
                          starting at absolute zero and increasing
                          without any known upper limit.</li>
                        <li><strong>Inventory or Resource Allocation</strong>:
                          Resource allocation policies, such as those
                          for virtual machines, may be based on known
                          minimum allocation thresholds but have
                          flexible or unbounded resource caps, depending
                          on availability.<br>
                          <br>
                          I am writing to ask whether anyone who worked
                          with such systems could confirm/deny that
                          those are real use cases. If so, would it be
                          satisfying enough to assert one-way
                          unboundness with instanceof checks, i.e. range
                          instanceof UnboundedEndRange &&
                          !(range instanceof UnboundedStartRange). Would
                          appreciate any feedback.</li>
                      </ul>
                    </div>
                  </div>
                </blockquote>
              </div>
            </div>
          </div>
        </blockquote>
      </div>
    </blockquote>
    <br>
  </body>
</html>