Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

The whole idea of having Ranges of things without an obvious step function seems backwards to me.


You don't really have it.

In rust the (useful) trait implementations on `Range<T>` only exist for `T: Step`.

Sure you can create other `Range<T>`'s but you can't use them for anything useful. (Ok, if they are PartialOrd you still can use `contains` and `is_empty`).

The article makes it look like a lot of problems comes from rust being too generic over the range type but that's not the case (expect for contains requiring a reference, but then BigNum's are a thing too).

I.e. the only reason why you can create a `Range<Vec<Mutex<Rc<String>>>>` is because it doesn't hurt anyone to allow me to do so. But I won't be able to use that rang for anything. It won't implement `is_empty`/`contains` nor will it be Iterable. Heck it doesn't even implement `Clone`. But non of the implementations around iterability, is_empty, contains etc. get in practice any problem because of this type being valid.

Instead the mentioned problems come mainly from:

- start <= end not being enforceable at type level as a fallible range constructor would have a horrible UX.

- Range<usize> if used for indexing treating things like 5..0 as "out of bounds" while for iterating it's just an "empty" sequence (which is not nice but a very reasonable decisions generally improving usability in practice due to how the range types are normally used in rust but confusing for some less common use case).

- The person somehow being hung up on the exact definition of "out of bounds" not being clear enough defined in the function documentation of a experimental nightly API which is perma-unstable, i.e. we are basically speaking about internal (but visible) implementation details of the standard library...


Well, the std lib disagrees with you. In Rust, type definitions tend to be maximally generic and restricted with traits only in their implementation. Have a look at BTreeMap for example:

   pub struct BTreeMap<K, V> {
       root: Option<node::Root<K, V>>,
       length: usize,
   }
The two type parameters are unbounded, this gives flexibility in the implementation because it allows you to define separate `impl` blocks where the bounds are different and more specific to their use case.

Have a look, https://doc.rust-lang.org/src/alloc/collections/btree/map.rs...

Sometimes the bounds are just Clone, other times they are more complicated Ord bounds for functions like `get`.

This is the way Rust libraries are written, it's very flexible and it's the right choice IMO.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: