state of ranges

H. S. Teoh hsteoh at quickfur.ath.cx
Wed Dec 13 19:52:30 UTC 2017


On Wed, Dec 13, 2017 at 12:33:02PM -0700, Jonathan M Davis via Digitalmars-d wrote:
> On Wednesday, December 13, 2017 11:33:35 Steven Schveighoffer via 
> Digitalmars-d wrote:
> > I don't think there's a requirement for empty not to do any work, it
> > just has to return the same value each time.
> 
> IIRC, when this was discussed previously, it was decided that you
> really couldn't do work in empty. The problem is that under some
> circumstances at least, it's perfectly legitimate to skip calls to
> empty (e.g. if you already know that there's plenty of elements left
> in the range, because you've called save previously and have iterated
> through at least that many elements in another copy of the range or
> because the range has length). it was decided that you really couldn't
> do work in empty. It might be legitimate if your range was not a
> forward range, but it would only work under cirmustances where it
> would be impossible to know whether there are elements left in the
> range or not without calling empty - which is not the case when
> dealing with forward ranges.
[...]

Basically, it comes down to (1) doing the least amount of work necessary
to get your job done; and (2) programming defensively, i.e., assume the
worst about user code, or, don't assume anything more than what the API
dictates.

(1) From the range user's POV, the range API essentially says that if
.empty is true, then you can call .front and .popFront.  Doing the least
amount of work means you don't have to call .empty if you already know
beforehand it would have returned false. Similarly, it's legal to call
.popFront without calling .front (or .empty) in between, if you already
know beforehand .empty won't become true in the meantime.

(2) From the range author's POV, assuming the worst means not assuming
that user code will follow a particular sequence of calls to the range
API, other than what is required by the API itself. That is, if your
.empty would have returned false, then assume that somebody will call
.front or .popFront without calling .empty. Don't assume that someone
will always call .empty first.

(OTOH, the range API does require that .empty be false before .front and
.popFront are called, so you shouldn't need to check .empty yourself in
the implementation of .front and .popFront, i.e., avoid doing more work
than necessary.)


Whether you do work in .empty or .front is not really relevant, as long
as ANY sequence of valid range API calls will always produce the same
result.  And by any sequence of valid calls, of course, I include
sequences that don't include .empty if somehow the user code already
knows beforehand when .empty will become true.  I.e., the sequence
{ r.popFront; r.popFront; r.popFront; ... ; .front } ought to produce
the correct result, as long as .empty never becomes true in the meantime
(and .empty does not need to be called explicitly).

If you can do work in .empty (or .front) while still fulfilling this
requirement, then great.  If not, perhaps you should find a different
implementation strategy.

Everything else is just pudding.


T

-- 
Guns don't kill people. Bullets do.


More information about the Digitalmars-d mailing list