2 ms·
The terrible thing about the C++ and Rust solutions is that one needs to understand many idioms and quirky syntax choices in order to comprehend what's going on
by blub 8y ago
The terrible thing about the C++ and Rust solutions is that one needs to understand many idioms and quirky syntax choices in order to comprehend what's going on.
In Python it's blindingly obvious what is happening: one is creating a group of 3 values, where the values are in specific ranges if a certain condition is met. Itertools.count() is perhaps opaque, but otherwise this is literally how the code reads!
Rust is already going into the weeds after the first '=' with its flat_maps and (1..) = c, whatever the heck that means and the C++ code is not even worth talking about.
Performance is not an excuse, since loops can solve this with good performance and probably the best readability.
- DougBTX 8y ago> and (1..) = c, whatever the heck that means The 1..=c is Rust syntax for an inclusive range. Rust also has syntax for ranges that exclude the last value like Python’s range(1, c + 1), which is 1..(c + 1). Using that would make it look more like the other examples, though since the language has syntax for the idea “1 to c inclusive”, it makes sense to just use it. For comparison Ruby uses a..z and a...z for inclusive and exclusive ranges respectively. I like that Rust’s inclusive range is more visually distinct, and I can see why they went for a symbol that implies the last element “equals” another value, but it does look unusual at first glance.
- mclehman 8y agoThis exact thing is one feature I like about Perl 6 and (minorly) dislike about Rust. In P6, 1..10 is exactly the range you'd expect, while ^ is used to exclude either end of the range. For example, 1..^11 is the same as 1..10, as is 0^..^11 (can't say I've ever needed that, but I could see a couple of possible uses). This also carries over into range syntactic sugar. ^10 is shorthand for 0..^10, and as a result ^@list.elems is a list of valid indices of a list. I personally find Rust's syntax noisier, but it's a small issue.
- mehrdadn 8y agoA downside of 1..10 is, how do you represent an empty range starting from 1? 1..0? That looks so weird... I'd expect it to mean a backward range starting from 1 and going up to 0 inclusive. A nice thing about end-exclusive notation is you can denote backward ranges, forward ranges, and empty ranges with the same notation.
- DougBTX 8y ago> In P6, 1..10 is exactly the range you'd expect That syntax is impressive, handles all four possibilities nicely. However since reading this short article by Dijkstra, I’ve been convinced that 0..N ranges (inclusive start, exclusive end) are the way to go whenever there’s a choice: http://www.cs.utexas.edu/users/EWD/ewd08xx/EWD831.PDF http://www.cs.utexas.edu/users/EWD/ewd08xx/EWD831.PDF There's certainly a mental benefit of having made a choice and being consistent, which I think is possible with any of the options, but I find the argument of having length = end - start compelling. It does fall down in some cases, eg when looking for a range over all unsigned ints, as the total number of uints isn’t a uint itself (as uints start at zero), so some way to represent a rage that is inclusive of both ends is still needed.
- b2gills 8y agoAs a minor nit, it may be better to use `@list.keys` to get a Sequence of indices. Especially if you want it to work when `@list` is `lazy`.