1. 42
  1.  

  2. 4

    I came across this article after working on some code that deals with, well, ranges of ordered values.

    I thought “a natural way to express those is with the Range type!”

    Yeah. I have no idea how to write a Rust function that takes either of a Range or a RangeInclusive value (without wrapping it in an enum or treating it as an iterator, which does not apply in my situation). There’s all sorts of weirdness with lifetimes and the borrow checker.

    It’s a pain, which makes me sad because it would be fluent and intuitive to use range literals for a large part of what I’m doing.

    1. 13

      I have no idea how to write a Rust function that takes either of a Range or a RangeInclusive value

      You need param: impl RangeBounds<T>. This actually is a part of ranges api that works Ok.

      https://doc.rust-lang.org/std/ops/trait.RangeBounds.html

      1. 2

        I’ve been gradually incubating a crate at work for dealing with intervals in general, including functions for things like interval comparison, difference and intersection, etc. The core representation I’ve settled on is type Interval<T> = (Bound<T>, Bound<T>). This doesn’t get everything you want (it’s still possible to eg construct an interval where the lower bound is above the upper bound) but it’s reasonably low overhead and begins to get you where you need to go.

        As part of all this work I’ve been submitting a few PRs to flesh out methods on the Bound type (which is in the stdlib) - we now have as_ref, as_mut, map, etc., which is nice.

      2. 2

        The problem is Range is overloaded: it’s too flexible, it wants to be everything.

        Agreed, Scala also suffered from this issue in various ways. The implementation complexity of trying to be everything for everyone is huge.

        E. g. you can create an “overful range” (that contains more than Int.MaxValue steps, due to the bad decision that collections can only contain Int.MaxValue elements), but you can’t actually reject it during construction, because the user could supply a custom step size later on that could turn such an overful range back to a normal one.

        Then all the fun stuff dealing with floating point and BigDecimal values (e. g. does 0.1 to 0.5 by 0.1 contains 0.3?). It’s a big mess there too.

        Range::is_empty() could be written naturally instead of a a bizarre way just for NaNs

        To be honest, this seems to be not a fault of Rust’s Range, but a symptom of the brokenness of the Ord/PartialOrd hierarchy in Rust.

        1. 3

          Why is it a bad decision that collections can only contain Int.MaxValue elements?

        Stories with similar links:

        1. My Least Favorite Rust Type via liftM 10 months ago | 63 points | 8 comments