-
Notifications
You must be signed in to change notification settings - Fork 1k
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
goog.math.RangeSet and goog.math.Range appear to have inconsistent semantics #1077
Comments
Wow, thanks for pointing that out. That's a pretty glaring inconsistency. In my opinion, Range is in the wrong, and in an ideal world we would change it to be half-open. Unfortunately, Range has a number of issues - for instance, its constructor allows passing numbers in either order, so it's kind of fundamentally closed. We have thousands of usages of Range and I fear that trying to change this behavior would be infeasible. There's far fewer uses of RangeSet, but I don't really want to change it to be closed. Also, RangeSet is pretty crufty (i.e. it implements the ES4 iterator pattern) and doesn't have a number of features I'd consider essential in a range set, so I'm not convinced we even necessarily want to double down on it. That said, I'm testing out what would happen if we were to make the change(s) to Range. |
One way forward would be to take advantage of the point vs value naming inconsistency.
If wholesale replacement is up for consideration, I suggest replacing Where
Where
Where
Where
Any design isomorphic with that implied by the above examples would do. I recommend the design and implementation be reviewed by a suitably qualified mathematician. |
For functions that take two arguments, which together specify a half-open interval, I have found it useful to name the parameters
This makes these functions easier to predict and makes it easier for calling code to avoid off-by-one errors (whether 1 whole unit or 1 ulp).
|
Guava has been quite successful with named factories for ranges: I looked into making the two changes I was curious about: (1) checking the order in the Range constructor, and (2) simply changing it to be open on the upper side. The precondition caused about 50-100 unique errors in our codebase and would be quite difficult to change. The semantic change was actually pretty innocuous and only seemed to break one usage, surprisingly. I'm not super happy with just that change (again, due to what I said above where the constructor parameters are interchangeably closed/open depending on the order) but we could potentially actually get away with it. Some mitigating possibilities would be to add a define to opt-out of the precondition and that would allow proper semantics while still giving us a pass for the existing breakages. |
Also, in terms of trying to insert a semantic distinction between "point" and "value", I'm not at all keen on that option. It's not something that's at all obvious without reading the documentation or implementation, since those terms don't actually have that meaning. |
Although I have used parts of Guava many times, I had not previously noticed the |
https://github.com/google/closure-library/blob/master/closure/goog/math/rangeset.js#L29
https://github.com/google/closure-library/blob/master/closure/goog/math/range.js#L176
It appears
goog.math.RangeSet.prototype.containsValue
interprets eachgoog.math.Range
as representing a half-open interval, butgoog.math.Range.containsPoint
uses a closed interval interpretation.This might be consistent if there is an undocumented implication that a numeric point is a distinct concept to a numeric value, but it seems more likely this is unintentional.
The text was updated successfully, but these errors were encountered: