Range.init does not imply Range.empty==true
H. S. Teoh
hsteoh at quickfur.ath.cx
Thu Dec 20 13:08:46 PST 2012
On Thu, Dec 20, 2012 at 09:58:22PM +0100, Jonathan M Davis wrote:
> On Thursday, December 20, 2012 12:48:10 H. S. Teoh wrote:
> > I noticed that in some places in Phobos range-related code, there's an
> > assumption that the following code works:
> >
> > auto someRangeFunction(R)(R range) {
> > ...
> > R helperRange = range;
> > ...
> > helperRange = R.init;
> > assert(helperRange.empty);
> > ...
> > }
> >
> > Exercise for the reader: spot the bug.
> >
> > Hint: what if R is an InputRangeObject?
>
> takeNone should be used to empty a range - though whether you get the same
> type depends on the range (e.g. you'll get the result of takeExactly(range, 0)
> for an InputRangeObject). And it works the way that it does precisely because
> there's no guarantee that R.init is even usable. For instance, you can't use
> init with Voldemort types (which is the main reason that I seriously question
> the wisdom of Voldemort types at this point).
But .init isn't merely used when you explicitly invoke it. It's the
default value of struct fields, for example (see below).
> However, any range which is a struct whose init value _isn't_ empty is
> wrong. We should be be able to rely on that at least.
[...]
No we can't. For example:
auto someRangeFunction(RoR)(RoR ror) {
struct Helper {
RoR _ror;
ElementType!R _current;
this(RoR r) {
_ror = r;
assert(_current.empty);
}
}
return Helper(ror);
}
If RoR is an array of class objects, the assert line will segfault
because _current.init is null. Conceptually speaking, I agree that a
null object is an empty range, but in code, .empty is undefined because
you can't invoke a method through a null reference.
T
--
ASCII stupid question, getty stupid ANSI.
More information about the Digitalmars-d
mailing list