Overhauling the notion of output range

Steven Schveighoffer schveiguy at yahoo.com
Mon Jul 12 12:41:29 PDT 2010


On Mon, 12 Jul 2010 15:18:17 -0400, Andrei Alexandrescu  
<SeeWebsiteForEmail at erdani.org> wrote:

> On 07/12/2010 01:47 PM, Steven Schveighoffer wrote:
>> On Mon, 12 Jul 2010 13:49:50 -0400, Andrei Alexandrescu
>> <SeeWebsiteForEmail at erdani.org> wrote:
>>> Yes. The point is that with a delegate you must choose between
>>> accepting E and E[]. Given the constraint, it's better for everyone to
>>> accept E[] and let put() take care of the occasional E by doing the
>>> wraparoo (&elem)[0..1].
>>
>> But given a delegate that takes a single element, there's no way to wrap
>> it so it can be an output range. Yet such a delegate can easily be
>> something that outputs something.
>
> void delegate(int) perItem;
> void ofCourseThereIsAWay(int[] items) {
>      foreach (e; items) perItem(i);
> }

Yeah, I realized after posting that it was incorrect :)  But encouraging  
this kind of thing is probably not fostering efficient code (roll your own  
delegate when the compiler complains).  It goes to my example with  
dcollections and add.

>> I could loop on an array of strings of one character, and output that to
>> a valid output range no problem. The only thing that solves this problem
>> correctly is buffering.
>
> I don't understand the point here.

My point is, if the reason behind requiring arrays instead of single  
elements is to force efficiency, then the reason is flawed.  I can make  
inefficient code even when having to pass arrays to an output range.

To solve this, you could make an output range that buffers elements until  
it has enough to pass to an underlying sink that takes an array of  
elements.  The point is, you've only gone halfway to ensuring efficiency.   
But going the full way means you are imposing possibly bad buffering  
semantics on everything.  If you can only go halfway, then I think the  
design is more annoying than successful.

>
>> What if I have my own container types that are large chunks of data, but
>> don't happen to define the input range primitives? Why should I be
>> artificially prevented from using those as input to output ranges?
>
> I don't understand this either.

Well, I had started constructing an example of how this would work, but I  
realize, I have no idea how you intend to use such a delegate as an output  
range...  I don't really know how such output ranges will be generically  
usable in conjunction with output ranges which support the put interface.

>
>> Really to me, you are saying, "I want your delegate to be efficient",
>> but you defined something that is related to that in a small set of
>> circumstances (when the arrays being passed in are large).
>
> What I'm saying is, "If you know how to output one item you may as well  
> output several, as I'm producing them in bulk".

I have no control over being able to output items in bulk or not, all I  
have is a delegate.  What do I do?

>> Here's a proposal for put/isOutputRange which would solve my problem and
>> not have any for loops in it:
> [snip]
>
> I'm uncomfortable about allowing inefficiency by design if I can help  
> it, but I guess the costs all depend on the costs of trafficking one  
> item.

I'm unsure how it will work either.  I admit now that I didn't think  
through how this will be used.  I imagined that the delegate version would  
be substituted for an output range which takes an element at a time, but  
now I'm not sure how you could write generic code that does that, given  
that the delegate must take an array of elements instead.  I guess I'll  
wait to see how it works before objecting any further.

-Steve


More information about the Digitalmars-d mailing list