I'll ask again: what is the type signature of from_start_and_len? Are both T? If so, what of the signed types and negative length? Perhaps T and Into<T::Unsigned> to at least remove the negative-ness concern? Should there be a try_ variant that catches that and overflow? If it is "just" Add-gated, what about floating point types? What is f32::Unsigned if that path is chosen? Or perhaps this only makes sense for usize at all?
I think it'd be reasonable for the length to be a usize and the start to be anything implementing Step, with a panicking version and an Option version.
That actually wouldn't work. To utilize Step, you'd have to pass by ownership internally, as the methods take Self by value. That's the only way you'd know what the end value is, but now you no longer have the start value to store.
I understand this is an example and donât want to get too deep into bikeshedding but do think itâs worth noting that Range::from_start_and_len is so absurdly verbose that I suspect nobody will ever use it, which somewhat defeats the point of something which is purely a convenience method.
If a ..+ b was implemented as syntax sugar for a .. (a + b) I think it would work exactly the way people would expect it to, and in those cases.
It can't be exactly this, because people will expect a to be evaluated only once. It has to be something like { let $temp = a; $temp .. ($temp + b) } instead, and that runs us into the issues discussed up above with what happens when a isn't Copy.
Personally I'd be fine with a requirement for a to be Copy though. My reaction to the "what about "a".."z"?" example up above is "I really don't want people spelling that "a" ..+ 26" (not least because they probably should have written "a" ..+ 25, but +26 is the one that looks right if someone's not reading carefully).
I think it'd be reasonable to have Range::from_start_and_len and Range::try_from_start_and_len as full functions you can write out (one panicking/wrapping and the other returning an Option), and then we can use ..+ or whatever other operator we want as a shorthand, like how ints have long method names for me to specify that I want .wrapping_add or .saturating_add when it's important to explicitly handle overflow, or I can just use + when I don't need to.
I sometimes write code where Range::try_from_start_and_len(start, len).unwrap_or(/* whatever */) would be important to show that the case where len doesn't fit has been thought about and handled appropriately, and the verbosity isn't that bad when you have LSP-backed completion.
Note that I might be able to agree about 'a'..+25 (a Range<char>), but what string comes "25th after" "a"? If one limits themselves to lowercase ASCII values, it would be "aaaaaaaaaaaaaaaaaaaaaaaaaa". But then "ab" is unreachable via ..+ syntax.
nitpick: "a".."z" would really be "a"..+24 which was not the proposal, because here we(?) would want Range::from_start_and_len("a", 26) which looks totally reasonable to me; whereas "a"..+x doesn't tell me if x is the total len or the offset from the start.
Youâre right about the issues with it needing to be Copy and I was sloppy not including the placeholder variable, but Iâm not sure I follow why it should be "a"..+25 rather than "a"..+26. If itâs meant to be short for "a"..("a" + 26) then aside from the fact that
this should probably be characters rather than strings (as one of the other responses points out), and
this doesnât mean anything at all under the syntax sugar proposal, which was kinda the point of suggesting it (namely: keep it limited to the things which make unambiguous sense with the syntax),
I think it should be +26 and not +25 since .. is an exclusive range so the number is the length of the range and 'a' + 26 is the character after 'z' as it should be.
There is a natural way to define steps on strings which is used frequently in theoretical computer science for algorithms/proofs which enumerate all strings: you simply change the ordering such that all shorter strings appear before all longer strings (equivalently, left pad the strings with â-1 charactersâ to the same length before comparison). Unfortunately, this would be mismatched with Rustâs Ord implementation for strings/vectors so cannot be used to implement Step for strings.
Either way, however, Iâm hard pressed to imagine a case where what you want is a range of specific length over strings rather than characters since even under this definition, between "z" and "aa" you have an annoying to compute number of hundreds/thousands of strings including non-alphabetic and, more broadly, non-printable characters that youâd need to account for.
You're right, I forgot that .. is exclusive of the endpoint -- which means the original example of 'a' .. 'z' is probably incorrect, and I think that's actually an argument in favor of adding ..+.