Accessors, byLine, input ranges

Steven Schveighoffer schveiguy at yahoo.com
Fri Jan 29 07:49:34 PST 2010


On Fri, 29 Jan 2010 10:31:28 -0500, Andrei Alexandrescu
<SeeWebsiteForEmail at erdani.org> wrote:

> Steven Schveighoffer wrote:
>> On Fri, 29 Jan 2010 08:03:13 -0500, Michel Fortin  
>> <michel.fortin at michelf.com> wrote:
>>
>>> On 2010-01-29 06:25:44 -0500, Pelle Månsson <pelle.mansson at gmail.com>  
>>> said:
>>>
>>>> On 01/29/2010 05:48 AM, Michel Fortin wrote:
>>>>>  No. Calling byLine doesn't change the stream. It returns a different
>>>>> view of stdin, which can be used to modify the stream, or not. I  
>>>>> think
>>>>> it should be a property. If it was 'getNextLine' then it should be a
>>>>> function. As a proof, this doesn't have any effect:
>>>>>  stdin.byLine;
>>>>  It reads a line off stdin. Try it.
>>>
>>> Ah, I see, you're right. Silly me for not trying.
>>>
>>> So it's not an accessor after all. The problem is that, even  
>>> disregarding the property syntax, the name strongly suggests it's an  
>>> accessor, but it has side effects, which it shouldn't. Either we  
>>> change the name to something else, like 'consumeLines()', or we make  
>>> it behave like an accessor. I'd go for the second option.
>>>
>>> The basic problem lies in the very basic definition of an input range.  
>>> Due to its interface (popFront + front), an input range is forced to  
>>> consume the its first element by its mere existence. I think  
>>> constructing an input range shouldn't have side effects. It should be  
>>> more symmetrical with an output range. It could have just one  
>>> function, 'take' to get the next element, and now byLine could work  
>>> correctly.
>>  Hey, it's that dead horse again, let's beat it!
>>  Andrei and I and several others discussed this ad infinitum.  You will  
>> never convince Andrei that his design is wrong :)
>
> Which debate are you referring to?

hm... let me dig it up.  (unwillingly)

http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=90971

>
>> The truth is, the fact that byLine modifies stdin by its mere existence  
>> proves to be inconsequential.  Nobody will fetch the byLine property  
>> without using it.  It's still an accessor.
>
> Yah, though I agree it's nicer to not prime the line in the constructor.

This would help, but you still have to be careful with streamed ranges.   
The valid point Michael brought up is the following:


	// fetch 3 lines:
	string[] consume(3, stdin.byLine);
	// now fill a buffer
	ubyte[] buffer;
	buffer = stdin.rawRead(buffer);

	E[] consume(E, R)(int count, R range) {
		E[] elements;
		foreach (i; 0..count) {
			elements ~= range.front;
			range.popFront();
		}
		return elements;
	}


Note the extra popFront.  So the loop must be rewritten:

if (count != 0) // base case, need special case for this
{
   int i = 0;
   while(!range.empty) // he forgot this condition
   {
      elements ~= range.front;
      if(++i == count)
         break;
      range.popFront();
   }
}

ugh... much simpler with a true stream-like range that supports what is  
natural for streams:

for(int i = 0; i < count && !range.empty; i++) {
    elements ~= range.get();
}

But of course, then this function doesn't work for other range types.  I  
decided in that discussion long ago that stream ranges were going to suck.

-Steve



More information about the Digitalmars-d mailing list