Range API
Olexandr Rotan
rotanolexandr842 at gmail.com
Thu Sep 26 13:07:59 UTC 2024
Researching the of deriving some iterable representations from ranges, and
I am not here with the good news.
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.
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.
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.
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.
There are a few solutions to this:
1) Define ton of overrides for factory methods and specialized types for
this (uhh, sounds awful)
2) Introduce new interface, say Discrete<T>, that defines T increment()
(and possible T decrement()) methods. From now on, there are 2 branches:
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.
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).
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.
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?
Best regards
On Tue, Sep 24, 2024 at 5:11 PM Alan Snyder <javalists at cbfiddle.com> wrote:
> 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
> 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
> 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
> is not represented in the type system.
>
> Having said that, I’m not sure that a general abstract interface would be
> useful for this example.
>
> On Sep 24, 2024, at 2:13 AM, Olexandr Rotan <rotanolexandr842 at gmail.com>
> wrote:
>
> 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.
>
>
> - *Date/Time Handling (Historical or Forecast Data)*: When dealing
> with events that started at a specific time but have no known end (e.g.,
> open-ended employment contracts or ongoing subscriptions)
> - *Stream Processing (Real-time Event Streams)*: 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.
> - *Data Pagination (Fetch Until Condition)*: 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).
> - *Auditing and Monitoring*: 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.
> - *Scientific or Statistical Ranges*: 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.
> - *Inventory or Resource Allocation*: 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.
>
> 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.
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/core-libs-dev/attachments/20240926/c424b197/attachment.htm>
More information about the core-libs-dev
mailing list