Accessors, byLine, input ranges

Michel Fortin michel.fortin at michelf.com
Fri Jan 29 09:14:13 PST 2010


On 2010-01-29 11:54:41 -0500, "Steven Schveighoffer" 
<schveiguy at yahoo.com> said:

> On Fri, 29 Jan 2010 11:33:17 -0500, Michel Fortin  
> <michel.fortin at michelf.com> wrote:
> 
>> On 2010-01-29 11:18:46 -0500, Andrei Alexandrescu  
>> <SeeWebsiteForEmail at erdani.org> said:
>> 
>>> It should work for stream ranges if front() checks the "filled" flag  
>>> and eats the next line if false, and popFront clears the "filled" flag.
>> 
>> So now you want the front to fetch from stdin on the first call? It's  
>> the same problem as 'byLine' eating the first line when you create it:  
>> neither one or the other should affect the stream.
> 
> No, you're reaching here :)  What Andrei is doing is acknowledging that 
>  front has already performed the job of popFront.  Because of the 
> nature of  streams, you cannot get the data from the stream, and leave 
> it on the  stream at the same time.  It's just not feasible.
> 
> What the solution Andrei came up with does is to make stream ranges 
> behave  as close as possible to forward ranges.  That small 
> inconsistency will not  hurt you because most of the time you are not 
> calling front for an element  you don't intend to use.  And even within 
> that paradigm, you are even less  likely to use the stream in another 
> capacity.

"will not hurt because most of the time"... surely you meant "will not 
hurt most of the time because". You're acknowledging it's an 
inconsistency and that it'll hurt.


> In other words, as the last usage of a range in an algorithm function,  this:
> 
> r.front;
> r.popFront();
> 
> is way more likely than:
> 
> r.popFront()
> r.front;

Yeah, it's less likely to be a problem. But "less likely to be a 
problem" does still does not make things reliable. Something reliable 
works all the time, or it just doesn't work and tells you.

And I'd argue that it's very likely that an algorithm hits the problem, 
check this:

	skipEmptyLines(stdin.byLine);
	string line = stdin.readln;

	void skipEmptyLines(R)(R range) {
		while (!range.empty && range.front == "")
			range.popFront;
	}

skipEmptyLine works right with ranges, but not with a stream. On the 
last loop, it calls range.front, which removes a line from the stream, 
and then say it's finished.

The truth is that this algorithm doesn't work with streams as it relies 
on a buffer being available. But it still compiles, silently 
introducing a bogus behaviour. If byLine defined only a 'take' 
function, we wouldn't have this problem as skipEmptyLines wouldn't 
compile, forcing you to use some kind of buffered stream or another 
algorithm that works correctly with streams.


-- 
Michel Fortin
michel.fortin at michelf.com
http://michelf.com/




More information about the Digitalmars-d mailing list