Output range primitives

H. S. Teoh via Digitalmars-d digitalmars-d at puremagic.com
Wed Jul 5 15:07:46 PDT 2017


On Wed, Jul 05, 2017 at 03:28:31PM -0600, Jonathan M Davis via Digitalmars-d wrote:
[...]
> The reality of the matter is that output ranges have never been well
> fleshed out. They seem to have been mainly created in order to have
> the opposite of input ranges, but they were never designed anywhere
> near as thoroughly as input ranges.
> 
> For some stuff to work well, we really do need some sort of property
> analogous to length which indicates how many more elements could be
> put into the output range, and having something like full that was
> analagous to empty would make sense as well. As it stands, you
> basically get to put elements into a range until it throws, because
> it's full, and while that makes sense under some circumstances, in
> others, it is most definitely not ideal.

The way I see it, isOutputRange defines a bare minimum, no-frills output
range.  Just like plain input ranges, it doesn't give us much, but does
give us enough to get by, i.e., a .put method for writing stuff into it.
This provides the "base concept" that additional functionality can be
added onto, akin to forward ranges, bidirectional ranges, etc..

It seems clear that there's at least a subconcept of output range that
has limited capacity.  I'm not sure what's a good name for it, but
perhaps a FiniteOutputRange could be a tentative name. So you'd have:

	Output Range:
		Defines a .put method

	Finite OutputRange (inherits from Output Range):
		Defines a .full method that indicates when the output
		range is full.

I wouldn't commit to a .length method, because there may be some output
ranges that cannot commit to a specific length, but do know when they're
full.  Instead, we could have a hasLength template that checks whether a
specific output range has a .length method.  An output range with a
.length method would be expected to also be a finite output range (i.e.,
has .full), and .length should return 0 when .full is true.


> Also, std.digest introduced a primitive called finish (if I remember
> the name correctly) which basically "finishes" an output range so that
> it's possible for an algorithm to do something to it after it's been
> filled (e.g.  if you had to do a checksum on the data and add it to
> the end or something).  But while I believe that std.digest uses it
> consistently, it's never been formalized beyond that.
[...]

IMO .finish is too specific of an idea to be formalized as part of a
generic output range concept.  A better idea might be a flushable output
range with a .flush method that performs some action on the data that's
accumulated in the output range so far, and resets it back to a state
where it's not full. The model I have in mind here is a buffer that can
be flushed to disk once it's full, thus emptying it out again for reuse,
or a digest algorithm that needs to perform some action, like write a
checksum to the end of the data, and afterwards resets its state so that
it can compute the checksum of a new segment of data.

It's unclear, however, whether .flush (or .finish) should be part of a
distinct derivation tree from a plain output range, or whether it should
be somehow related to finite output ranges. I.e., whether we should have
a linear progression of output ranges:

	Output range -> finite output range ->(?) flushable output range

or a non-linear hierarchy:

	               Output range
		      /            \
	Finite output range      Flushable output range

Can there also be an output range that's both finite and has a .flush
method?  Seems possible.  Or perhaps .flush is an orthogonal aspect that
should be treated separately, e.g., with a hasFlush template akin to
hasLength for testing whether an output range has a .flush method.

More thought needs to be put in to formalizing all of this.


T

-- 
Making non-nullable pointers is just plugging one hole in a cheese grater. -- Walter Bright


More information about the Digitalmars-d mailing list