Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed Ranges and Range Interface #138

Open
thomasnield opened this issue Jul 14, 2018 · 20 comments
Open

Closed Ranges and Range Interface #138

thomasnield opened this issue Jul 14, 2018 · 20 comments

Comments

@thomasnield
Copy link

thomasnield commented Jul 14, 2018

This issue is for conversation regarding the proposal for Exclusive Ranges and a Range Interface.

Pull Requestion: #137

@Wasabi375
Copy link
Contributor

I think there are a few things that should change:

  1. The Range interface should contain properties describing whether start and end are inclusive.
  2. I think the definition of open and closed ranges also needs to be refined. As far as my understanding of maths goes I would expect an open range to not include either endpoint, yet your example for an OpenRange contains the start value.
  3. This means that we need 4 different ranges: open, closed, IncludingStart, IncludingEnd. For the later 2 we would need a better name.

@LouisCAD
Copy link
Contributor

From the Contracts section:

For the OpenRange implementations, the lowerBound/start must be less than the upperBound/endExclusive. Otherwise the range should be empty.

0 downTo -10 is a valid range in Kotlin which doesn't follows this statement. I think this contract could be changed or dropped.

@thomasnield
Copy link
Author

thomasnield commented Jul 14, 2018

@Wasabi375 Well by that standard, ClosedRange should not be inclusive then either, and it is already an incumbent range type in Kotlin. I personally think my proposed names are fine and practical: ClosedRange, OpenRange, and later ExclusiveRange. Also, I can't think of many use cases for a fully ExclusiveRange anyway, although I'm sure they are out there.

I think indicators on Range for inclusivity/exclusivity on each point can be added later. For now, I recommend keeping it simple and don't make the Range do too much. If someone needs it that badly they can do a type check.

@LouisCAD Fair enough, but aren't those Progressions? That might be a separate KEEP but useful nonetheless.

10.0 downTo 1.0 step .5

I could have used that in my temperature schedule for the TSP.

That needs to be planned carefully though. For instance, how do we handle a DoubleProgression without a step? How do we control inclusivity/exclusivity?

@Wasabi375
Copy link
Contributor

@thomasnield No, following the standard terminology used in mathematics an open interval does not include either of its end points while a closed interval includes both of them. Than there is a half open interval which only includes one endpoint.
I know in kotlin they are called rang, but it is the same thing.
The names I would suggest would be: OpenRange, ClosedRange, LeftExclusiveRange, RightExclusiveRange.

@Wasabi375
Copy link
Contributor

As to the inclusivity indicators: I think adding will be no cost at all. They will just be a readonly property which all implementations override to either return true or false. This is safer than to assume, that no user would create their own custom range type (maybe for BigDecimal or some complex number type).

@thomasnield
Copy link
Author

thomasnield commented Jul 14, 2018

@Wasabi375 Or StartExclusiveRange and EndExclusiveRange 🤔, I guess I'm not opposed to calling my proposed need EndExclusiveRange. But if we are going to go that route, there's a larger issue with the start not being called startInclusive in the incumbent ClosedRange. If we really are going to consider ranges with start exclusivity, we need to address that.

I'd like to see use cases for StartExclusiveRange or a fully exclusive OpenRange. If start-exclusive ranges are never used, what's the point of killing ourselves over that start property? Can we kick that can down the road?

And let's keep in mind, just because supporting start exclusivity is mathematically correct, it does not mean it will have use cases in a generalized programming language.

I'm not sure what to do with the inclusivity indicators. I feel they add clutter and I can't think of use cases for them. Whenever you implement your own Range in my opinion, the onus of not screwing up the implementation is solely on the developer, and I don't see how the indicators enforce any behavior.

@Wasabi375
Copy link
Contributor

I think with adding lowerBound and upperBound we should think about deprecating start and endInclusive anyways.

I'd like to see use cases for StartExclusiveRange or a fully exclusive OpenRange. If start-exclusive ranges are never used, what's the point of killing ourselves over that start property? Can we kick that can down the road?

When dealing with pricing models I had to use both start and end inclusive ranges. As far as I remember startInclusive was more common than endInclusive but it was more equal than you might expect. I guess open ranges can be useful in validation and testing of calculations.


As for the inclusivity indicator, I was thinking about a custom range, where the inclusivity could be changed by the user, but I think this goes beyond this KEEP, so let's forget about it.

@thomasnield
Copy link
Author

With your pricing model example, you mean exclusive start ranges right?

Also, I posted this on MathExchange.

https://math.stackexchange.com/questions/2851657/what-are-real-world-use-cases-for-start-exclusive-ranges-intervals

@Wasabi375
Copy link
Contributor

Yes, I mean I had to use both ranges, which included the start and not the end, and ranges, which included the end and not the start. Imagine your histogram example just with the lower bound excluded and the upper bound included.

@thomasnield
Copy link
Author

I'll update the proposal and present all the approaches we discussed. I think we need to support start exclusivity after your input. Good talk.

@thomasnield
Copy link
Author

Proposal has been updated. The new types I documented are:

  • Range
  • OpenRange
  • OpenStartRange
  • OpenEndRange

@Wasabi375 I added you as a contributor, thanks for your helpful considerations and advisement.

@HaasJona
Copy link

Please consider taking some inspiration from Guava's Range class: https://github.com/google/guava/wiki/RangesExplained

It has worked very nicely in my projects so far.

@thomasnield
Copy link
Author

@HaasJona I think we are pretty aligned with Guava, other than Kotlin-izing it a little.

I think I'm going to create a separate KEEP for continous progressions, like 12..0 downTo 0 step 0.5

@voddan
Copy link
Contributor

voddan commented Jul 22, 2018

@thomasnield I think this proposal needs a similar API review analyses of other languages and frameworks. For example, how Python and other "math" languages handle this, what are the pros and cons of their implementations. Also, Guava seems to have similar APIs, why not include their analyses, as well as their usages and possibly discovered pain points.

@thomasnield
Copy link
Author

@voddan done. Gave mention to Python, R, and Google Guava.

@mkobit
Copy link

mkobit commented Mar 21, 2019

Stumbling upon this after looking at ClosedRange in the stdlib - would really appreciate the ability to represent half-open ranges with stdlib types. As it stands today, representing a half-open time interval (for example with Instant or some other java.time type) isn't possible.

@hamoid
Copy link

hamoid commented Feb 15, 2022

I think I'm going to create a separate KEEP for continous progressions, like 12..0 downTo 0 step 0.5

Is there such a KEEP already? I work with Kotlin and 2D / 3D graphics and such progressions would often simplify my code.

@Whathecode
Copy link

Whathecode commented May 11, 2022

I'm considering creating a kotlin-interval library to provide similar functionality to something I implemented in C# before, and is suggested here. It's a base class I used quite extensively in my C# projects. To give an example use case, I used this to render timelines and to more easily calculate zooming/scrolling/scaling operations.

If I don't get around to this and it may be of any inspiration, I simply had a base generic Interval class.

As type parameters it takes both T and TSize:

  • T: The type used to specify the interval, and used for the calculations.
  • TSize: The type used to specify distances in between two values of T.

In an old blog post of mine I elaborate a bit more, including this example code snippet to get a feel for the API:

// Mockup of a GUI element and mouse position.
var timeBar = new { X = 100, Width = 200 };
int mouseX = 180;
 
// Find out which date on the time bar the mouse is positioned on,
// assuming it represents whole of 2014.
var timeRepresentation = new Interval<int>( timeBar.X, timeBar.X + timeBar.Width );
DateTime start = new DateTime( 2014, 1, 1 );
DateTime end = new DateTime( 2014, 12, 31 );
var thisYear = new Interval<DateTime, TimeSpan>( start, end );
DateTime hoverOver = timeRepresentation.Map( mouseX, thisYear );
 
// If the user clicks, zoom in to this position.
double zoomLevel = 0.5;
double zoomInAt = thisYear.GetPercentageFor( hoverOver );
Interval<DateTime, TimeSpan> zoomed = thisYear.Scale( zoomLevel, zoomInAt );
 
// Iterate over the interval, e.g. draw labels.
zoomed.EveryStepOf( TimeSpan.FromDays( 1 ), d => DrawLabel( d ) );

@Whathecode
Copy link

I started work on this in this repository. Going smoothly so far. 🥳

@ilya-g
Copy link
Member

ilya-g commented Jul 22, 2022

With the planned introduction of rangeUntil operator, we're proposing an alternative approach for representing open-ended ranges. See details in the KEEP #314.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants