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