diff --git a/text/0000-range_redesign.md b/text/0000-range_redesign.md new file mode 100644 index 00000000..bf5d2018 --- /dev/null +++ b/text/0000-range_redesign.md @@ -0,0 +1,88 @@ +- Feature Name: range_redesign +- Start Date: 31/03/2019 +- RFC PR: (leave this empty) +- Pony Issue: (leave this empty) + +# Summary + +A Range reimplementation that includes the features from collections.Reverse together with a more comprehensive and coherent API. A reference implementation can be found here: https://github.com/chobeat/pony-range-proposal + +# Motivation + +The existence of Range and Reverse as separate classes, each one with their own limitations, to cover a use case that in most languages is addressed by a single API highlights the possibility for an improvement. Having a single, well-tested implementation to generate numeric ranges will improve the quality of life of new developers and possibly reduce unexpected behaviors for a core piece of the stdlib. +For example in the existing implementation it is possible to generate infinite ranges without any explicit control. To check that a range is infinite, the user has to call the dedicated function (`is_infinite`) to be sure that its range will terminate. This unloads onto the user a lot of unnecessary checks that could be incorporated into the Range class. In addition to that, the current implementation doesn't allow to express a range spanning over a whole data type since it makes assumptions on the exclusiveness of the right bound. This prevents the user from creating a range that includes the max element of a given data type. + +One major conceptual change is to make the direction of the Range more implicit in the API and determined by the runtime values of the Bounds. Before this was more explicit since there were two distinct classes to cover both use cases. The direction was unambigous but it was less intuitive for people coming from other languages where a split of the two concerns (increasing and decreasing ranges) is not so common. On top of this, in a scenario where both directions are valid, with the previous implementation it was required to involve two different classes and a check on the bounds to pass, while now this would be covered transparently. + +# Detailed design + +The new implementation should fullfil the following design principles: + +* be able to generate all the possible ranges, increasing and decreasing, for all the data types, without incurring in overflow errors. +* offer a unified, usable, coherent API with the possibility to specify inclusive or exclusive bounds. To achieve this, the definition of the bounds and the range should be independent. The Range class should offer helper methods to cover the most common cases without explicitely instancing the bounds. +* never raise errors but instead return an empty list. This decision arises from the assumption that a majority of ranges are defined with bounds known at compile time while declaring ranges using runtime values is less common. The error handling in that case has to be done by calling the `is_invalid()` method. A version of the class with explicit errors can be considered. + +The reference implementation solves these problems in the following way: + +* implements a trait `Bound[T]`, implemented by two classes: `Inclusive[T]` and `Exclusive[T]` to represent the bounds. Each one of them will be able to return the value to be used to define the range in the case that they are used as an upper or lower bound. +* implements a class `Range` with a default constructor that respects the existing API +* implements a more flexible constructor with the following signature: + `new define(b: Bound[T], e: Bound[T], step: T=1)`. +* Defines Step so that it cannot be negative or zero. In that case the range is considered empty. +* Supports the notion of range direction. If b