how to skip the next (n) item & continue from (n+1) with a range ? e.g. in File(fn).byLine();

Ali Çehreli acehreli at yahoo.com
Tue Jun 23 03:54:46 UTC 2020


On 6/22/20 2:37 PM, mw wrote:

 > On Monday, 22 June 2020 at 20:58:58 UTC, Ali Çehreli wrote:
 >
 >> Others have other explanations for this but my understanding is about
 >> exception safety: If it changed internal state and returned the front
 >> object, you would no be able to make a function like popFront()
 >> strongly exception safe. (There are ample documentation for this topic
 >> in C++ circles.)
 >
 > That's one consideration. But, it will be more interesting in knowing
 > (based on actual usage):
 >
 > (a) how many bugs % are due to exception un-safe

I am not claiming that strong exception safety is the reason for Phobos 
design. However, knowing what I know, I would use the same primitive 
operations. It's the same with e.g. C++ as well: != end(), operator*, 
operator++. And operator++ does not return the current object either.

Even if zero bugs are due to exception un-safe, a library designer would 
not oversee that knowledge. It is impossible to make an interface 
strongly exception safe but the reverse is always possible.

 > (b) how many bugs % are due to front / popFront separation?

I made the mistake of forgetting to call popFront() perhaps 10 times and 
got stuck in an infinite loop and quickly hit a segmentation fault and 
that was it.

 > And which is more bug-prone for a typical programmer? my gut feeling is
 > (b), at least we just saw one in this thread.
 >
 >
 > And
 >
 > -- loop thru a static structure content like a simple array, why we need
 > to worry about exception safe?

*If* strong exception guarantee is needed, it doesn't matter whether 
it's a simple array or not.

 > -- loop thru dynamically generated content, esp. network or more
 > external complex structure may worth considering exception safety. But
 > even there, do people always need to call !range.empty() check first?
 > when it's not empty, how much more exception un-safety that
 > popAndReturnFront() can introduce than the combination of `front(); ...;
 > popFront();"?

It has been demonstrated on a Stack type that conflating top() and pop() 
cannot be made strongly exception safe. It's the same with front() and 
popFront().

 > And why not provide a popAndReturnFront(), and let the user decide based
 > on his/her own actual usage?

Because if the primitives were empty() and popAndReturnFront(), then it 
wouldn't be made strongly exception safe. With the current primitives of 
empty(), front(), and popFront(), it's possible to implement 
popAndReturnFront(). I like the following one that I wrote in three 
minutes. :)

import std.stdio;

auto popAndReturnFront(R)(ref R range) {
   import std.range : empty, front, popFront, ElementType;
   import std.typecons : Nullable, nullable;

   if (range.empty) {
     return Nullable!(ElementType!R)();
   }

   scope (success) range.popFront();
   return nullable(range.front);
}

void main() {
   auto range = [ 1, 2, 3 ];
   while (true) {
     auto front = range.popAndReturnFront;
     if (!front.get()) {
       break;
     }
     writeln(front);
   }
}

 >> Another reason is cohesion: We want functions to have as little
 >> responsibility as possible (ideally single).
 >
 > Again we have to weight which way is more bug-prone, any actual
 > statistics on the above (a) v.s (b)?

I am not aware of any bugs related to the separation of front() and 
popFront().

Ali




More information about the Digitalmars-d-learn mailing list