Range API

Olexandr Rotan rotanolexandr842 at gmail.com
Mon Sep 23 19:02:57 UTC 2024


Hello, Brian

Another consideration I'd like to put on the table is: can it be a value
> type?  Because an immutable range


This was in my thoughts. I would even say it must be a value type. However,
I considered not bothering the Valhalla team unless this API was at least a
candidate.

As has been pointed out already, one would prefer to use a Comparator as a
> witness to ordering rather than the much weaker Comparable.



> I think the algebraic operations as you've proposed them (union,
> intersection, etc) are a bit of a mess, union especially.


As I said, there are a lot of issues with it. Of course I would love to
have such an option in the API, but it has a lot of clashes with range
arithmetic. Maybe I was too fast with the assumption that range
arithmetic is needed in the first place, at least as instance methods. I
will look into possibilities of extracting arithmetic into separate classes
like Math and make Range nore skewed towards data structure with ability to
manipulate it in the procedural fashion. I see that there is still a demand
for things like unions (range sets), and subsequently there will be a
demand for comfortable and standard ways to produce them.

I would want to see Range implement Iterable (yes, I understand this rules
> out some possible types of ranges), as iterating over the elements of a
> range is one of the most likely operations.


I previously did some research on producing streams out of ranges, it has
shown itself pretty well, but API was a bit unintuitive. I will look into
it more carefully though, when more prioritized tasks are completed.

Thanks for your feedback, I appreciate it.

Best regards

On Mon, Sep 23, 2024 at 9:47 PM Brian Goetz <brian.goetz at oracle.com> wrote:

> This is a nice start.  I'd like to add a few comments to help set
> expectations and to guide future explorations here.
>
> Starting with a "main goal" of "putting it in the JDK" is putting the cart
> before the horse.  The main goal should be to solve the problem well
> enough, for a broad enough variety of uses, that it might be _considered as
> a candidate for the JDK_ (possibly with some additional work), but it
> should stand well enough on its own.  (The Joda Time -> java.util.time
> transition is a good example of doing this right.)  Build a good thing
> first, then let's have a conversation about whether it belongs in the JDK.
>
> Another consideration I'd like to put on the table is: can it be a value
> type?  Because an immutable range (and we wouldn't consider anything else)
> is an ideal candidate for being a value.  (This is one of many "is it going
> where the language is going" questions; I'll keep the rest of those to
> myself for now.)
>
> As has been pointed out already, one would prefer to use a Comparator as a
> witness to ordering rather than the much weaker Comparable.
>
> I would want to see Range implement Iterable (yes, I understand this rules
> out some possible types of ranges), as iterating over the elements of a
> range is one of the most likely operations.
>
> I think the algebraic operations as you've proposed them (union,
> intersection, etc) are a bit of a mess, union especially.
>
>
>
>
>
> On 9/22/2024 3:01 PM, Olexandr Rotan wrote:
>
> Hello everyone! I am writing here today to invite everyone to participate
> in the discussion regarding the Range APi proposal I have made into JDK.
> Here is the pull request link: https://github.com/openjdk/jdk/pull/21122,
> and PR text:
>
> This pull request describes the methods of the Range<T> interface. The
> Range<T> interface represents a bounded or unbounded range. (From now on,
> range, span and interval are used interchangeably, but docs only use
> "range")
> Goals:
>
>    -
>
>    *Main goal. Standardization of the Range/Interval API:* The primary
>    objective of this effort is to provide a standardized interface for working
>    with ranges or spans of time (or any ordered types). Many existing
>    libraries offer their own custom implementations of ranges, and they differ
>    in significant ways, making it harder to use and combine across different
>    codebases. Standardization will ensure consistency, interoperability, and a
>    more predictable interface across various contexts.
>    -
>
>    *Versatile range operations:* provide a comprehensive API for
>    manipulating and querying ranges, especially those representing time
>    periods or numerical intervals. The API simplifies common tasks like
>    checking containment, overlaps, or adjacency between ranges.
>    -
>
>    *Support for unbounded ranges:* Unlike many existing libraries, which
>    assume intervals are always bounded, this API aims to fully support
>    unbounded intervals. Users will be able to define ranges with open starts
>    or ends, making it suitable for temporal data that spans indefinitely in
>    one direction, such as future projections or historical data with unknown
>    starting points.
>    -
>
>    *Performance efficiency:* The API aims to provide optimized for
>    performance implementation, that takes advantage of all possible
>    simplifications and short-circuits.
>    -
>
>    *Consistency with existing libraries:* To aid adoption, the API should
>    be familiar to developers who have used popular libraries like NodaTime,
>    Joda-Time, Three-Ten Extra, and Boost Date_Time, but with enhancements for
>    unbounded intervals, negative ranges (?), and optional return types instead
>    of null values.
>
> Non-Goals:
>
>    -
>
>    *Handling complex data structures beyond smple ranges:* This API is
>    not intended to manage or represent complex data structures beyond ranges.
>    For example, ranges that involve intricate internal states, like
>    non-contiguous ranges (?) or ranges with multiple gaps, are out of scope.
>    -
>
>    *Overly simplifying range types:* While ease of use is a goal, its is
>    not an aim to remove support for advanced cases like unbounded or negative
>    ranges, even if this results in slightly more complex implementations. The
>    API should not be skewed towards being purely a simple data structure for
>    bounded ranges.
>    -
>
>    *Application-specific logic:* The API is meant to be domain-agnostic
>    and general-purpose. It is not intended to allow to embed
>    application-specific logic, such as calendar-based date manipulations or
>    domain-specific business rules for interval comparison.
>    -
>
>    *Replacing existing libraries:* The goal is not to replace established
>    libraries like Joda-Time or ThreeTen-Extra, but rather to augment these
>    ideas with support for unbounded ranges and additional arithmetic
>    operations. Although, it is a goal to provide interface that could
>    exisiting libraries could easily retrofit into.
>
> Motivation
>
> The primary motivation behind standardizing the Range API is the *lack of
> an established, universal interface* for handling ranges or spans across
> various domains. Developers are often forced to work with different,
> incompatible range implementations across libraries or to re-implement
> common functionality themselves. This leads to redundant code, increased
> dependencies, and greater chances for errors.
>
> In many software systems—whether in scheduling, auditing, access control,
> or financial services—ranges are used to represent periods of time,
> numerical intervals, or validity spans. Without a standardized API,
> developers must contend with diverse implementations that often differ in
> naming conventions, behavior, and supported features. These variations
> create unnecessary complexity, as developers must:
>
>    1.
>
>    *Introduce additional dependencies*: Many libraries provide similar
>    functionality for ranges, but since they are not interchangeable,
>    developers must often add extra dependencies to cover edge cases or
>    specific use cases that are not available in a single library. This bloats
>    the codebase and creates maintenance overhead.
>    2.
>
>    *Re-implement common logic*: In cases where no single library meets
>    the required needs, developers are forced to write their own range-handling
>    logic. This reinvention of basic operations such as intersection, union, or
>    containment leads to redundancy, increased likelihood of bugs, and
>    inconsistency in how ranges are handled across different parts of the code.
>    3.
>
>    *Fragmentation across domains*: Different libraries often define their
>    own range concepts (e.g., for date-times, numbers, or general comparisons),
>    which are rarely compatible with one another. This lack of compatibility
>    makes integration between systems difficult, requiring custom adapters or
>    conversions.
>
> By defining a standard Range API, the goal is to:
>
>    - *Reduce the dependency footprint:* A common, well-designed API for
>    ranges would eliminate the need to import multiple libraries just to handle
>    different types of ranges, reducing dependencies in projects and enhancing
>    maintainability.
>    - *Simplify code and increase reusability:* With a standardized
>    interface, developers can write range-related code once and reuse it across
>    projects and libraries, confident that the same semantics and operations
>    will apply consistently.
>    - *Minimize developer errors:* By providing a predictable and
>    well-documented interface, the likelihood of misunderstandings or incorrect
>    use of range operations will decrease. Developers can trust that operations
>    like intersections, unions, and comparisons will behave consistently,
>    regardless of the context.
>
> In essence, the lack of standardization in range operations creates
> unnecessary complexity, fragmentation, and redundant effort. A standardized
> Range API would provide clarity, reduce the need for additional
> dependencies, and enable more efficient, reusable, and error-free code
> across different projects and domains.
> Key API points Support of unbounded intervals
>
> API supports both one- and two-sided. Provided sample (draft)
> implementation for ChronoDateTime has 4 separate implementation for each
> type of ranges.
> Alternatives
>
>    - Many Libraries, like Luxon, C++ boost, NodaTime and many others,
>    arguably the most, fo not explicitly support unbounded intervals. This
>    reduces complexity of implementation, but takes away many possible
>    optimization for edge-cases. Alternative they propose is to use Instant.MIN
>    and Instant.MAX or similar to create unbounded-like intervals.
>
> Support for negative intervals,
>
> API supports both positive and negative and positive ranges. This is
> questionable and discussion is encouraged.
> Advantages
>
>    - Allows more flexible usage of API, which would be helpful for use
>    cases like diagrams visualization.
>
> Disadvantages
>
>    - Dramatically increases amount of boilerplate code inside the
>    implementations.
>    - Makes behaviour of potential methods like boolean endsBefore(T t) unintuitive.
>    Does this mean that end() is before that provided parameter, or latter of
>    bounds (i.e. start() for negative range and end() for positive).
>    - Limited usability scope. Most use cases would not benefit from
>    possibility of negative ranges creation, but would have to suffer
>    performance decrease.
>
> In general, either there should be support for negative ranges, or ranges
> might be end-exclusve, but not two at the same time, as having them both
> together dramatically increases complexity.
> Range is not Serializable
>
> Currently ranges are not Serializable. This is due to difficulties
> regarding using non-serializable interfaces, like ChronoDateTIme  in
> sample implementation.
> Alternatives
>
>    - Restrict range type variable to implement Serializable. I see this
>    option as undesiarable bacause of how much it narrows use of interface.
>
> Current interface methods list is minimal
>
> For now, API proposed contains minimal amount of methods that are used in
> range arithmetics. List of methods is supposed to change as discussion
> moves on.
> Generic Range class vs Rnage interface + specific inmplementations
>
> Currently, approach is to define interface and list of implementations.
> Advantages
>
>    - Ability to introduce specialized for type of range methods. For
>    example, Timespan could have Duration toDuration() method, potential
>    IntegerRange could have something like LongRange toLongRange() dur to
>    limitations of comparability between classes. This would be impossible with
>    structural class Range without declaring additional static utility methods.
>    - Enhanced validation of annotaion targets as classes, unlike
>    generics, arent erased.
>
> Disadvantages
>
>    - Increased amount of classes to maintain.
>    - Additional considerations would be required before extending Range
>    interface in case if hierarchy non-sealed to ensure backward compatibility.
>
> API Description NB: Since date ranges is supposed to be one of the most
> popular if not the most popular use case for range, date-time libraries
> were main reference for interface design.
> ------------------------------
> Section: Bounds General notes
>
>    - In *Boost Date_Time* (time_period.begin()), the start and end are
>    always defined, meaning there is no concept of unbounded intervals.
>    Similarly, some libraries like *Chrono* in Rust assume bounded
>    intervals by default. In fact, only a few libraries expose trully unbound
>    ranges. Although, while complexity of implementation is increased by this
>    corner cases, thier performance also vastly increased by cutting amount of
>    operations in each method at least in half (For two-way unbound interval,
>    almost all operations return constnat value).
>
> ------------------------------
> T start()
>
> *Description:*
> Returns the start of the range. If the range is unbounded at the start,
> this method throws an UnsupportedOperationException. This can be
> preemptively checked using isBoundedAtStart().
>
> *Alternatives:*
>
>    - Method could return Optional<T> instead of throwing an exception. I
>    see this two approaches roughly identical in terms of pros/cons score, so
>    suggestions are much appreciated.
>
> ------------------------------
> T end()
>
> *Description*:
> Returns the end of the range. If the range is unbounded at the end, this
> method throws an UnsupportedOperationException. Use isBoundedAtEnd() to
> check if the range is bounded.
>
> *Alternatives:*
>
>    - Simallarly to start(), method could return Optional<T> instead of
>    throwing an exception. I see this two approaches roughly identical in terms
>    of pros/cons score, so suggestions are much appreciated.
>
> ------------------------------
> boolean isBoundedAtStart()
>
> *Description*:
> Returns true if the range is bounded at the start. If unbounded, it
> returns false, meaning calling start() will throw an
> UnsupportedOperationException.
>
> *Alternatives*:
>
>    - *Joda-Time*, *NodaTime*, *Luxon*, and *Moment.js* do not explicitly
>    support unbounded intervals by default but can use null or special
>    values to represent unbounded starts.
>    - *Boost Date_Time* and *Chrono* don’t support unbounded ranges
>    directly, so this method is unnecessary.
>
> ------------------------------
> boolean isBoundedAtEnd()
>
> *Description*:
> Returns true if the range is bounded at the end. A false value means the
> range is unbounded at the end, and calling end() will throw an
> UnsupportedOperationException.
>
> *Alternatives*:
>
>    - Similar to isBoundedAtStart(), most libraries don’t have built-in
>    unbounded intervals, but the concept can be simulated using null,
>    minimal/maximal possible value etc. Pros and cons were described in API
>    notes.
>
> ------------------------------
> Section: boolean operations boolean contains(T instant)
>
> *Description*:
> Returns true if the given instant falls within the start and end bounds
> of the range, otherwise returns false.
>
> *Similar Methods in other libraries*:
>
>    - *NodaTime (Interval.Contains)*
>    - *Joda-Time (Interval.contains)*
>    - *Luxon (Interval.contains)*
>    - *Boost Date_Time (time_period.contains())*
>    - And many others...
>
> *Differences with existing APIs*:
>
>    - *Moment.js* doesn’t provide a direct contains method but the
>    moment-range plugin adds this functionality with range.contains().
>
> *Note*: this method is present in most interval implementations.
> Terefore, I concider as basic and unremovable from the API.
> ------------------------------
> boolean overlaps(Range<? extends T> other)
>
> *Description*:
> Checks if the current range overlaps with another range. Returns true if
> the two ranges overlap, otherwise returns false.
>
> *Similar Methods in other libraries*:
>
>    - *NodaTime (Interval.Overlaps)*
>    - *Joda-Time (Interval.overlaps)*
>    - *Luxon (Interval.overlaps)*
>    - *Boost Date_Time (time_period.intersects())*
>    - And many others...
>
> *Differences with existing APIs*:
>
>    - *Moment.js*: The moment-range plugin provides a similar overlaps() method
>    to check overlap.
>    - *Chrono* relies on custom interval intersection logic.
>
> *Note*: this method is present in most interval implementations.
> Terefore, I concider as basic and unremovable from the API.
> ------------------------------
> General notes on next two methods
>
> Most of the libraries propose API like isBefore(T point) or do not
> provide methods like this at all. Since current implementation throws an
> exception if interval is not bounded, trivial check for isBefore could
> become 4-6 lines long. The question basically comes down to whether the
> Range class should be more data-structure-like or object-like. I would
> argue that at least isBefore(T moment) is required, especially since
> ranges can be negative currently. Existence of boolean isBefore(Range<?
> extends T> other)and similarisAfter` is up to discussion.
> boolean isBefore(Range<? extends T> other)
>
> *Description*:
> Returns true if the current range is strictly before another range (i.e.,
> ends before the other range starts).
>
> *Differences with other libraries*:
>
>    - *NodaTime*: You’d manually compare End of one interval with the Start of
>    another.
>    - *Joda-Time*: Manual comparison with Interval.getEnd() and
>    Interval.getStart().
>    - *Boost Date_Time* and *Chrono* would use custom logic to compare
>    time_period or ranges of time, since they don’t have a direct
>    equivalent of isBefore().
>
> *Alternatives*
>
>    - Most of the libraries propose API like isBefore(T point) or do not
>    provide methods like this at all. Since current implementation throws an
>    exception if interval is not bounded, trivial check for isBefore could
>    become 4-6 lines long. The question basically comes down to whether the
>    Range class should be more data-structure-like or object-like. I would
>    argue that at least isBefore(T moment) is required, especially since
>    ranges can be negative currently
>
> ------------------------------
> boolean isAfter(Range<? extends T> other)
>
> *Description*:
> Returns true if the current range is strictly after another range (i.e.,
> starts after the other range ends).
>
>    - *Similar Methods*:
>       - Similar to isBefore(), manual comparisons are used in *NodaTime*,
>       *Joda-Time*, and *Luxon* an others.
>
> ------------------------------
> boolean isBefore(T point)
>
> *Description:*
> Determines if the span ends before the given point. This is useful when
> you need to check whether a time span occurs entirely before a specific
> point.
>
> *Alternatives*:
>
>    - Method could be removed from APi at all, if Range is desired to be
>    skewed towards being data structure.
>
> ------------------------------
> boolean isAfter(T point)
>
> *Description:*
> Determines if the span starts after the given point. This is useful when
> you need to check whether a time span occurs entirely after a specific
> point.
>
> *Alternatives*:
>
>    - Similarly to boolean isBefore(T point), method could be removed from
>    APi at all, if Range is desired to be skewed towards being data structure.
>
> ------------------------------
> boolean isNegative()
>
> *Description*:
> Returns true if the start of the range is after the end, indicating a
> "negative" range.
>
> *Alternatives:*
>
>    - if concidered too niche, negatie timespans could be removed from
>    model.
>
> *Note:* this one is most questionable for me. Do we really need negative
> ranges? This is most entirely required in numeric ranges and diagrams,
> while introdcues huge complexity overhead for majority that doesnt need
> this feature. Negativity might be confusing for users. Would love to hear
> thoughs on this matter
> ------------------------------
> Section: Range arithmetics Optional<Range<T>> intersection(Range<?
> extends T> other)
>
> *Description*:
> Returns the intersection of the current range with another range. If the
> ranges do not overlap, the result is an empty Optional. If they overlap,
> the intersection is returned.
>
> *Similar Methods*:
>
>    - *NodaTime (Interval.Intersection())*
>    - *Moment.js (via moment-range, range.intersect())*
>    - *Joda-Time (Interval.overlap())*
>    - And many others...
>
> *Differences with existing APIs*:
>
>    - *Boost Date_Time* returns an empty time_period if no overlap exists,
>    instead of an Optional. Some libraries return null (e.g., *NodaTime*).
>    - Other libraries return null if intervals arent overlapping. This is
>    undesrable, so optional returned instead.
>
> *Note*: this method is present in most interval implementations.
> Terefore, I concider as basic and unremovable from the API.
> ------------------------------
> Range<T>[] union(Range<? extends T> other)
>
> *Description*:
> Returns the union of two ranges. If the ranges overlap, the result is a
> single combined range. If they do not overlap, the result is an array of
> two separate ranges.
>
> *Differences with existing APIs*:
>
>    - *NodaTime* and *Joda-Time* support similar logic using custom union
>    handling.
>    - *Boost Date_Time* has no built-in union() function but you can write
>    custom logic to combine or separate intervals.
>
> *Note*: Behaviour of this method is up to change. Currently, it returns
> array for maximal performance, but it can (and most likely should) be
> wrapped in some monadic class. As an alternative, there may be support for
> non-continuous ranges (ones with gaps inside them), then this method should
> return thise kind of range.
> ------------------------------
> Optional<Range<T>> gap(Range<? extends T> other)
>
> *Description*:
> Returns the gap between two ranges, if they do not overlap. If they
> overlap, the result is an empty Optional.
>
> *Differences with existing APIs*:
>
>    - *NodaTime* and *Joda-Time* support custom logic to calculate the gap
>    using isBefore(), isAfter(), and manual calculations of the gap.
>    - Other libraries return null if intervals are overlapping. This is
>    undesrable, so optional returned instead.
>
> ------------------------------
> Section: potential methods boolean isEmpty()
>
> *Description:*
> Determines if the range is "empty,"
>
> Empty range is its own, separate type of range (basically opposite of
> unbounded range). There are many questions regrading this type of range. Is
> it bounded at start or end? If so, what should start() or end() return.
> Them throwing an exception would violate current contract between
> IsBoundedAtX() and 'x()` methods.
>
> *Advantages*
>
>    - Returning empty range instead of Optional might be more user-friendly
>
> *Disadvantages*
>
>    - One more concept in the API model
>    - Corner case in IsBoundedAtX() and 'x()` contract.
>
> Potential Methods for API Enhancement
>
> In this section, we explore methods that could be added to the API,
> comparing them with similar functionality in popular time-related
> libraries. These methods enhance the versatility and clarity of the
> Range<T> implementation, especially in the context of temporal, numeric,
> and other domain-specific ranges. Some of these methods are inspired by
> well-established libraries, while others are novel suggestions.
> ------------------------------
> boolean encloses(Range<? extends T> other)
>
> *Description*:
> Checks whether the current range completely encloses another range, i.e.,
> the other range starts after or at the start of the current range and ends
> before or at the end of the current range.
>
>    -
>
>    *Similar Methods in Other Libraries*:
>    - *NodaTime (Interval.ContainedBy)*
>       - *Joda-Time (Interval.contains)*
>       - *Luxon (Interval.contains)*
>       - *Boost Date_Time (time_period.contains())*
>    -
>
>    *Differences with Existing APIs*:
>    - Some libraries handle encloses() and contains() in the same method.
>       For clarity, this API can separate the two, where contains() is
>       used for checking individual points and encloses() is for
>       range-level comparison.
>
> ------------------------------
> boolean abuts(Range<? extends T> other)
>
> *Description*:
> Returns true if the current range abuts (i.e., touches but does not
> overlap) with another range. This method is useful when determining whether
> two ranges are adjacent but do not overlap.
>
>    -
>
>    *Similar Methods in Other Libraries*:
>    - *NodaTime (Interval.Abuts)*
>    -
>
>    *Alternatives*:
>    - Instead of this method, users could manually compare the end of one
>       range and the start of another, but including abuts() in the API
>       simplifies the logic and reduces error-prone comparisons.
>
> ------------------------------
> Range<T> extendTo(T point)
>
> *Description*:
> Returns a new range that extends the current range to include the given
> point. If the point is already within the range, it returns the current
> range. Otherwise, it extends either the start or end, depending on the
> point's position relative to the range.
>
>    -
>
>    *Similar Methods in Other Libraries*:
>    - *NodaTime* and *Joda-Time* do not have explicit methods for this,
>       but users can manipulate intervals manually.
>       - *Moment.js*: The moment-range plugin offers similar logic via
>       manual adjustments to the range.
>    -
>
>    *Advantages*:
>    - In contrast to manual adjustment, this method automates the process
>       of extending ranges, which can be useful in situations where ranges need to
>       be dynamically modified over time (e.g., expanding time intervals in
>       streaming data).
>
> *Alternatives*:
>
>    - Users could manually adjust the range using start() and end() "withers",
>    but an explicit extendTo() method offers a more intuitive, built-in
>    approach
>
> ------------------------------
> Range<T> shrinkTo(T point)
>
> *Description*:
> Returns a new range that shrinks the current range to exclude the given
> point, if possible. If the point is within the range, the range is modified
> so that it no longer includes the point. This is useful for splitting
> ranges or excluding unwanted time periods or values.
>
>    - *Similar Methods in Other Libraries*:
>    No major time libraries provide a direct equivalent to this
>    functionality, although similar operations can be manually performed by
>    manipulating start and end.
>
> *Alternatives*:
>
>    - Similarly to extendTo, users could manually adjust the range using
>    start() and end() "withers", but an explicit shrinkTo() method offers
>    a more intuitive, built-in approach.
>
> ------------------------------
> Range<T>[] difference(Range<? extends T> other)
>
> *Description*:
> Returns the difference between the current range and another range (XOR
> operations). If the ranges overlap, the result is a new range or two ranges
> representing the non-overlapping portions. If the ranges do not overlap,
> the result is the current range.
>
> *Adavntages*:
>
>    - This method simplifies computing the difference between two ranges,
>    reducing the need for manual boundary comparisons.
>    - Completes set of methods required for ranges arithmetics
>
> *Disdavntages*:
>
>    - THis method is inverse of union(Range<? extends T> other), so it has
>    same design problems as union.
>
> ------------------------------
> Range<T> clamp(Range<? extends T> bounds)
>
> *Description*:
> Clamps the current range to fit within the specified bounds. If the
> current range extends outside of the bounds, it is shortened to fit within
> the bounds. If the range already fits within the bounds, it is returned
> unchanged.
>
> *Advantages*:
>
>    - This method streamlines the process of adjusting a range to a set of
>    bounds, which is especially useful in time-based operations where ranges
>    must be constrained within specific periods (e.g., scheduling).
>
> ------------------------------
> boolean isContiguousWith(Range<? extends T> other)
>
> *Description*:
> Determines if the current range is contiguous with another range, meaning
> that the two ranges touch or overlap without leaving any gaps. This is
> particularly useful when combining ranges or ensuring that a sequence of
> ranges forms a continuous block.
>
> *Alternatives*:
>
>    - Users could manually compare the end and start of ranges to check
>    contiguity, but this method offers a more explicit and efficient way to
>    perform the check.
>
> ------------------------------
> Optional<Range<T>> asBounded()
>
> *Description*:
> Returns the bounded version of the current range, if one exists. If the
> range is already bounded, it returns the range unchanged. If the range is
> unbounded, the result is an empty Optional. Could be used as a monade for
> handling errors if range that is expected to be bounded, but unbounded one
> has been recieved.
>
> *Alternatives:*
>
>    - API could explicitly expose BoundedRange marker (or not marker)
>    interface to verify range that is recieved is bounded at compile time.
>    Interface could provide some adapter methods for converting
>    unknown-boundness ranges to bounded, and have specific behaviour for error
>    cases.
>
> Range<T>[] splitAt(T point)
>
> *Description*: Splits the current range into two sub-ranges at the
> specified point. If the point lies outside the range, it returns an array
> of length 1 with initial range. If rang contains() point, than array of
> length 2 is returned, whith two ranges splitted accross given point.
> List<Range<T>> splitInto(int n)
>
> *Description*:
> Splits the current range into n equal sub-ranges. If the range cannot be
> evenly divided, the last range may be slightly larger to accommodate the
> remaining span. Throws UnsupportedOperationException if range is at least
> half-unbounded.
> Stream<T> pointsFromStartToEnd(??? step)
>
> *Description*: Returns a list of points that are evenly spaced from the
> start to the end of the range, using the specified step size. Throws
> UnsupportedOperationException if range is isBoundedAtStart() returns
> false.
>
> *Note:* while this method could have various use cases, It is not clear
> how step could be provided. One of the options is to pass Function<T, T> that
> is invoked on each value until value is > end() instrad of constant step.
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/core-libs-dev/attachments/20240923/b4fc2729/attachment-0001.htm>


More information about the core-libs-dev mailing list