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.

Reply via email to