Reminds me of D at times. It has many fancy features and powerful metaprogramming. But it also comes with drawbacks, many simple language improvement proposals are being shot down because they break in presence of some advanced usage of those features.
`Range` was discussed a lot before being stabilized and it's drawbacks where well known when it was stabilized.
The reason it was stabilized that way anyway was because it happens to work out best for the most common use-cases.
It's more of a "practically use-full but theoretically imperfect compromiss" thing.
The main usage of range are:
1. To iterate over it
2. To slice things using it
Which is what it is focused on in it's design.
Sure ranges could be `Copy` but one of their main purposes is to be an iterator so it's reasonable to not make them copy as that would be a usability nightmare.
Sure it's strange that you can construct a invalid range and then panic when you use it to slice something. But the alternative would be to make the creation of range fallible which is a usability nightmare. Furthermore validity depends on what you use it one, so a backwards range might be a very reasonable thing for some use-cases so practically it's best to make every `Range` valid, but not necessary every usage of one.
Sure exclusive ranges based on start+end can't contain the maximal value but that's a fundamental property of exclusive ranges defined through start+end. There is a reason mathematics have 4 kind's of ranges (differing in exclusiveness in start/stop).
Sure `.contains` takes a reference, but that's a problem about how rust can't specialize traits in how they need
references for Copy methods. Not having that would prevent the usage of ranges of `BigNums` or similar reasonable usages.
Sure `RangeInclusive` could be made shorter but that also means you can't have empty inclusive ranges and you can't
use it directly as an iterator, which is probably the most
common use case of inclusive ranges.
All in all the `Range` types are a compromise optimized for it's most common use cases. That makes some parts sub-optimal if used for other cases but you can also always use your own types so that's not really a problem in practice.
Also he does some mistakes:
- You can't enforce `start <= end` at construction time without making the constructor fallible which would be a ergonomic nightmare. Which means that neither `[T]::get()`
or `Range.len()` would get faster nor would is_empty get
easier.
The last point also sadly means that for certain arithmetic high performance tasks it can make sense to not use the rust provided range type but a custom one.