Live data from Hacker News

My least favorite Rust type

ridiculousfish.com

181–190 of 298 posts

Re: My least favorite Rust type

#181

Earlier quoted context omitted.

I assume the issue is with Rust letting you create such a range and then having the bad stuff happen when you try to use it, rather than failing fast.

Whether 5..0 being an empty range is "bad stuff" or "good stuff" is a matter of perspective. It is often "good stuff" for me, when computing some indices to slice with. Panicking on construction would force one perspective on every use case.

> But why isn't it panicking on len()? How is 0 the right answer there?

- len is `ExactSizedIterator.len()` which is the length of `Range` as iterator, i.e. the number of items yielded by next. Which is 0.

- When slicing with 5..0 it threats it not as an empty iterator but as an out of bounds access. This is without question slightly inconsistent and not my favorite choice but was decided explicitly this way as it makes it much easier to catch bugs wrt. wrongly done slices. Also it only panics if you do Index which can panic anyway but it won't panic if you use e.g `get` where it return `None` so making it traet the "bad" empty case differently for slicing doesn't add a new error path, but doing so for iteration and `len` would add a new error path especially given that `ExactSizedIterator.len()` isn't supposed to panic as it's a size hint.

Re: My least favorite Rust type

#183

I actually love this type. Specifically because you can build ranges over complex key types. For example, two keys in a BTreeMap can be used to define a range selector to collect items out of the map, it made me very happy to be able to do this: https://github.com/bluejekyll/trust-dns/blob/main/crates/ser...

The example you provide appears to be using the same type for both beginning and ending values, and would also appear to explicitly provide an ordering (<=). Maybe I missed something, but that level of abstraction did not seem to be what was under indictment in the article, but rather scenarios where the types of first and last were disjoint, or the values were incomparable.

Re: My least favorite Rust type

#184

I can’t even figure out how to iterate over a Range of Vectors? iter and collect both don’t exist... Google doesn’t seem helpful either. I don’t know any rust but it seems unforgiving at the first hurdle here :-)

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

Re: My least favorite Rust type

#185
post #53

>This does mean writing for n in (1..10).iter(), but Rust already requires that for collections, so it’s more consistent. Even this needn't be the case. `Range` can implement `IntoIter` to plug into `for` loop syntax. Another related problem is that `SliceIndex` ( https://doc.rust-lang.org/std/slice/trait.SliceIndex.html ) trait, which is used to implement indexing, is perma-unstable. So, even if you build your own b…

The problem is that his/her proposal also says that start Now consider the usability nightmare `(1..10).unwrap()` would be and `&slice[(1..10).unwrap()]` and `(1..10).and_then(|range| slice.get(range))` instead of `slice.get(1..10)`.

That's the actual problem, not that `Range` implements iterator.

Oh and most ranges are used ad-hoc (created and then directly consumed) so for many use cases going with Range + IntoIterator would increase the overhead.

Besides that while SliceIndex is perma unstable, `Index` is not so if you control the container you can make it work alternatively you can always do `my_range.index(slice)`.

Re: My least favorite Rust type

#186
> Is this backwards range valid? Its len() is 0, it contains() nothing, it yields nothing as an iterator. But if you try to use it to index into a slice, you get a panic! So it looks valid but is primed to explode!

Rust has comparison traits... why aren't those involved here? It seems like it would be straightforward to ensure that any Range's start and end can only be Ord's, and that the first value must be > Range requires the borrow, so the vastly more common Range etc. forces it as well.

Not sure why this has to be the case. Why the implicit reference? Why not, when you want to use references in your range (a fairly exotic usecase), you have to do so explicitly?

  &vec1..&vec2

Re: My least favorite Rust type

#187

I actually love this type. Specifically because you can build ranges over complex key types. For example, two keys in a BTreeMap can be used to define a range selector to collect items out of the map, it made me very happy to be able to do this: https://github.com/bluejekyll/trust-dns/blob/main/crates/ser...

The example you provide appears to be using the same type for both beginning and ending values, and would also appear to explicitly provide an ordering (<=). Maybe I missed something, but that level of abstraction did not seem to be what was under indictment in the article, but rather scenarios where the types of first and last were disjoint, or the values were incomparable.

Range only has one type parameter. Thankfully, you really cannot have a range with an i32 on one end and a String on another.

It's also not possible to call methods like contains() on Range unless the type is (Partial?)Ord, because of the constraint on Idx in the impl which defines those methods.

Re: My least favorite Rust type

#188

> This is abusing the borrow checker as a bad linter. Range undermines the story of lifetimes and ownership, making the borrow checker feel arbitrary. This is the key part. You really shouldn't try to "censor" the math to "help" users. It just causes more pain. I'm recently been annoyed with the push back against "DynSized" again, which IMO is a symptom of the same thing. "DynSized" is the natural way to generalize R…

Are you sure about this? I've heard the quote applied specifically in the context of RAII, where he complained that there is no such thing as a generalized "resource", and that the same mechanism for handling memory access should not be used for file handles and texture maps. I don't have a link right now, but I'm pretty sure it was in his first "ideas for a programming language for games" video back in 2014. Seems t…

I remember his video on RAII. My opinion on his take is that it's pure tosh. Incidentally I also hate Golang... He's used to languages with thin abstractions like C where it's basically impossible to get anything done fast without dissociating allocation and creation (and in particular, allocation and mutation).

Modern languages and Rust specifically address that problem by letting you write clean programs with the illusion of immutability but still basically mutating state all over the place in the actual executable.

And that's if you care that much about speed. Even slow Rust is pretty fast, and the readability/consistency/maintainability benefit of RAII is immense compared to the tiny speed gains.

Re: My least favorite Rust type

#190

Also, fix the problem that Range can't do .len(): fn main() { let r = 0u64 .. 1; let n = r.len(); | ^^^ method not found in std::ops::Range println!("Hello, world! {}", n); } https://play.rust-lang.org/?version=stable&mode=debug&editio...

Interesting:

.len() is not the length of a slice induced by the range or the distance between start and end but instead it's the len method form `ExactSizedIterator`, which in turn is a "special case" of where `Iterator.size_hint()` is known to return a correct value.

The thing is `Iterator.size_hint()` does return a size, which is usize.

So `Range` can only implement `ExactSizedIterator` on 64-bit targets, which I guess is why someone decided that it's better to not implement it (at all) to not hinder portability of libraries as it would be quite easy to accidentally write a lib not working on 32 bit. Not sure if that is the right decision tbh.

Post reply on HN