Weird issue with std.range.iota.length

Steven Schveighoffer via Digitalmars-d digitalmars-d at puremagic.com
Fri Feb 12 08:35:08 PST 2016


On 2/12/16 10:59 AM, Jonathan M Davis wrote:
> On Friday, 12 February 2016 at 14:36:29 UTC, Meta wrote:
>> On Friday, 12 February 2016 at 08:11:57 UTC, Jonathan M Davis wrote:
>>> What it comes down to is that length should always be size_t. That's
>>> what it is for arrays, and that's what most code expects. Allowing
>>> other types just causes trouble for generic code. However, in the
>>> case of iota with long, if length is size_t, then on 32-bit systems,
>>> it's possible to have a range from iota which is longer than size_t
>>> can represent (much as it would normally be crazy to have a range
>>> that long). So, at some point, someone made it so that iota uses
>>> ulong for length instead of size_t when it's a range of longs or
>>> ulongs. It's the only thing in Phobos that does, and it causes
>>> problems. Changing it back to size_t has been discussed but not
>>> agreed upon. But we're between a rock and a hard place with this one.
>>> There is no clean solution.
>>>
>>> Personally, I'd very much like to see iota just always use size_t for
>>> length like every other range (the only ranges which would be
>>> affected would be ludicrously long anyway, and it would only affect
>>> 32-bit programs). But that hasn't happened yet, so iota over longs
>>> and ulongs doesn't behave nicely on 32-bit systems.
>>>
>>> Regardless of which way we go, the problem will _eventually_ go away
>>> when 32-bit systems finally die out, but that's likely to take a while.
>>>
>>> - Jonathan M Davis
>>
>> What about adding another overload of iota, say, iotaEx or something
>> along those lines. All it would do is the following:
>>
>> auto iotaEx(B, E)(B begin, E end)
>> {
>>     assert(unsigned(end - begin) <= size_t.max);
>>
>>     static struct Result
>>     {
>>         typeof(iota(begin, end)) payload;
>>
>>         @property size_t length()
>>         {
>>             return cast(size_t)payload.length;
>>         }
>>
>>         alias payload this;
>>     }
>>
>>     return Result(iota(begin, end));
>> }
>
> It would be far better IMHO to just do a check in iota and throw a
> RangeError if the length wouldn't fit in size_t. Having length ever be
> anything other than size_t is just going to cause problems with other
> ranges. On 32-bit systems, you lose out on the ability to have a range
> that covers all values of long or ulong, but that's of very limited
> usefulness anyway, and as long as the number of elements is no greater
> than size_t.max, it would be fine - which would cover virtually all use
> cases. No, it's not perfect, but allowing length to be anything but
> size_t just causes bugs - especially in generic code.

Just because you have a range with a ulong length doesn't mean you are 
going to iterate the entire thing.

What we need is this:

standardLength(R)(R r) if (isInputRange!R && hasLength!R)
{
    static if(is(typeof(r.length) == size_t)) return r;
    else
    {
       static struct Result
       {
          R wrapped;
          size_t length() { return to!size_t(wrapped.length); }
          alias wrapped this;
       }
       return Result(r);
    }
}

-Steve


More information about the Digitalmars-d mailing list