Bug #13663

`String#upto` doesn't work as expected

Added by sos4nt (Stefan Schüßler) about 2 years ago. Updated about 2 years ago.

Target version:
ruby -v:
ruby 2.4.1p111 (2017-03-22 revision 58053) [x86_64-darwin15]


Given that String#upto uses String#succ to generate successive values, I'd expect

'x'.upto('ac').to_a #=> []

to return:

["x", "y", "z", "aa", "ab", "ac"]

Instead, an empty array is returned.

This seems to depend on whether the the receiver is greater than the argument or not:

'x' <=> 'ac' #=> 1

It works just fine in this case:

#    "ab", "ac", "ad", "ae", "af", "ag", "ah", "ai", "aj", "ak", "al",
#    "am", "an", "ao", "ap", "aq", "ar", "as", "at", "au", "av", "aw",
#    "ax", "ay", "az", "ba", "bb", "bc", "bd", "be", "bf", "bg", "bh",
#    "bi", "bj", "bk", "bl", "bm", "bn", "bo", "bp", "bq", "br", "bs",
#    "bt", "bu", "bv", "bw", "bx", "by", "bz", "ca"]

Presumably because of:

'b' <=> 'ca' #=> -1


Updated by zverok (Victor Shepelev) about 2 years ago

I believe that problem here is how to provide consistency between succ and <=> for arbitrary length strings.

  1. For most of the real use cases, 'x' > 'ac' is sane (like sorting strings);
  2. Things using succ (like upto and ranges) should check that begin is lower than end;

So... I believe that it is only reasonable to have (1) and (2), though sometimes it leads to "inconsistencies", like described above. If you do a lot of stuff with making ranges from "x" to "ac" it is probably better to have dedicated value object class, with redefined <=> and succ

Updated by Hanmac (Hans Mackowiak) about 2 years ago

Also i think its a bit to much optimised.

because i tried to overwrite the String#<=> method, directly or with Refinements, and it didnt work as i want it to.

what works is using my own Value Object Class.

Updated by sos4nt (Stefan Schüßler) about 2 years ago

I'm not asking for consistency between String#succ and String#<=> (although that would be desirable). I do understand that the discrepancy may result in surprising results when generating sequences via Range because Range relies on these methods. Range checks via <=> if the value generated by succ is indeed a successor.

But String#upto doesn't have the limitations Range has. It doesn't have to work with arbitrary objects and it doesn't have to depend on <=>. It can apply whatever logic is needed to ensure a sane result.

Also available in: Atom PDF