digitalmars.D.learn - how to skip the next (n) item & continue from (n+1) with a range ?
- mw (18/18) Jun 22 2020 Hi,
- Steven Schveighoffer (14/31) Jun 22 2020 I wouldn't recommend it, instead do a while loop:
- mw (8/20) Jun 22 2020 Thanks.
- mw (7/29) Jun 22 2020 I'm asking this, because here it need to be range.popFrontN(n+1);
- mw (4/22) Jun 22 2020 or
- H. S. Teoh (14/16) Jun 22 2020 [...]
- mw (6/15) Jun 22 2020 This is valid reason, but as I replied in the other post: it
- Steven Schveighoffer (10/45) Jun 22 2020 `n` actually isn't defined, you defined it in a comment in your original...
- mw (6/10) Jun 22 2020 In this case, it's caused by underlying structure may reuse the
- =?UTF-8?Q?Ali_=c3=87ehreli?= (12/16) Jun 22 2020 Others have other explanations for this but my understanding is about
- mw (22/33) Jun 22 2020 That's one consideration. But, it will be more interesting in
- =?UTF-8?Q?Ali_=c3=87ehreli?= (49/76) Jun 22 2020 I am not claiming that strong exception safety is the reason for Phobos=...
- kinke (2/2) Jun 22 2020 If you are referring to the next line, not the next n lines,
- kinke (2/4) Jun 22 2020 [Please discard, that'd obviously be skipping the *current* line.]
Hi, I need this logic: ``` auto range = File(fn).byLine(); foreach (line; range) { if (comeCond(line)) { // skip the next n line // and continue the foreach loop from the (n+1) line } else { regularProcess(line); } } ``` Is it possible to do this in a foreach loop? If not, how can I achieve that, esp. when reading a file line-by-line? do I have to read the whole file into memory, and split by line and using regular `for` loop?
Jun 22 2020
On 6/22/20 3:53 PM, mw wrote:Hi, I need this logic: ``` auto range = File(fn).byLine(); foreach (line; range) { if (comeCond(line)) { // skip the next n line // and continue the foreach loop from the (n+1) line } else { regularProcess(line); } } ``` Is it possible to do this in a foreach loop?I wouldn't recommend it, instead do a while loop: auto range = File(fn).byLine; while(!range.empty) { auto line = range.front; if(someCond(line)) { range.popFrontN(n); } else { regularProcess(line); range.popFront; } } -Steve
Jun 22 2020
On Monday, 22 June 2020 at 20:00:50 UTC, Steven Schveighoffer wrote:I wouldn't recommend it, instead do a while loop: auto range = File(fn).byLine; while(!range.empty) { auto line = range.front; if(someCond(line)) { range.popFrontN(n); } else { regularProcess(line); range.popFront; } }Thanks. so `front` is peek, and `popFront` is the pop action whose return type is `void`, why we need two *separate* calls instead of just let `popFront` return T (or do we have another function for this)? i.e if the user forget `popFront`, it will prone to infinite loop bug?
Jun 22 2020
On Monday, 22 June 2020 at 20:46:30 UTC, mw wrote:On Monday, 22 June 2020 at 20:00:50 UTC, Steven Schveighoffer wrote:I'm asking this, because here it need to be range.popFrontN(n+1); i.e. bug-prone can be fixed by: auto line = range.front; range.popFront; // pop immediatelyI wouldn't recommend it, instead do a while loop: auto range = File(fn).byLine; while(!range.empty) { auto line = range.front; if(someCond(line)) { range.popFrontN(n);so my question.} else { regularProcess(line); range.popFront; } }Thanks. so `front` is peek, and `popFront` is the pop action whose return type is `void`, why we need two *separate* calls instead of just let `popFront` return T (or do we have another function for this)? i.e if the user forget `popFront`, it will prone to infinite loop bug?
Jun 22 2020
On Monday, 22 June 2020 at 20:49:55 UTC, mw wrote:On Monday, 22 June 2020 at 20:46:30 UTC, mw wrote:eitherOn Monday, 22 June 2020 at 20:00:50 UTC, Steven Schveighoffer wrote:I'm asking this, because here it need to beI wouldn't recommend it, instead do a while loop: auto range = File(fn).byLine; while(!range.empty) { auto line = range.front; if(someCond(line)) { range.popFrontN(n);range.popFrontN(n+1); i.e. bug-proneorcan be fixed by: auto line = range.front; range.popFront; // pop immediatelyof course.
Jun 22 2020
On Mon, Jun 22, 2020 at 08:51:49PM +0000, mw via Digitalmars-d-learn wrote: [...][...] This is dangerous, because it assumes .front is not invalidated by .popFront. It will not work, for example, with byLine because .front returns a buffer which is reused by .popFront (a so-called "transient range"). In the realm of defensive programming, it is better to make less assumptions (don't assume .front remains valid after .popFront) than add implicit assumptions (range is non-transient) that may break in subtle ways that are not immediately obvious. T -- Why ask rhetorical questions? -- JCauto line = range.front; range.popFront; // pop immediately
Jun 22 2020
On Monday, 22 June 2020 at 21:22:10 UTC, H. S. Teoh wrote:On Mon, Jun 22, 2020 at 08:51:49PM +0000, mw via Digitalmars-d-learn wrote: [...]This is valid reason, but as I replied in the other post: it depends on the actual underlying data structure and usage scenario, so: "why not provide a popAndReturnFront(), and let the user decide based on his/her own actual usage?"[...] This is dangerous, because it assumes .front is not invalidated by .popFront. It will not work, for example, with byLine because .front returns a buffer which is reused by .popFront (a so-called "transient range").auto line = range.front; range.popFront; // pop immediately
Jun 22 2020
On 6/22/20 4:49 PM, mw wrote:On Monday, 22 June 2020 at 20:46:30 UTC, mw wrote:`n` actually isn't defined, you defined it in a comment in your original code ;) I just threw it in there. Of course, make sure it works how you are expecting, I don't know what your code is doing.On Monday, 22 June 2020 at 20:00:50 UTC, Steven Schveighoffer wrote:I'm asking this, because here it need to be range.popFrontN(n+1);I wouldn't recommend it, instead do a while loop: auto range = File(fn).byLine; while(!range.empty) { auto line = range.front; if(someCond(line)) { range.popFrontN(n);i.e. bug-prone can be fixed by: auto line = range.front; range.popFront; // pop immediatelyThis is a bad idea, once you popFront, the original front is possibly invalid (and technically is the case for byLine).There is no requirement to actually construct members. e.g. popFrontN calls popFront N times, but does not actually invoke front at all. Separating the concerns is for correctness and performance. -Steveso my question.} else { regularProcess(line); range.popFront; } }Thanks. so `front` is peek, and `popFront` is the pop action whose return type is `void`, why we need two *separate* calls instead of just let `popFront` return T (or do we have another function for this)? i.e if the user forget `popFront`, it will prone to infinite loop bug?
Jun 22 2020
On Monday, 22 June 2020 at 21:27:12 UTC, Steven Schveighoffer wrote:In this case, it's caused by underlying structure may reuse the `byLine` buffer, but I'm asking a more general question about range interface: why not provide an extra popAndReturnFront(), and the user to choose in the actual usage scenario.auto line = range.front; range.popFront; // pop immediatelyThis is a bad idea, once you popFront, the original front is possibly invalid (and technically is the case for byLine).
Jun 22 2020
On 6/22/20 1:46 PM, mw wrote:so `front` is peek, and `popFront` is the pop action whose return type is `void`, why we need two *separate* calls instead of just let `popFront` return TOthers 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.) Another reason is cohesion: We want functions to have as little responsibility as possible (ideally single).(or do we have another function for this)?There are many useful functions in std.range: https://dlang.org/phobos/std_range.html The "take" and "drop" functions may be useful. Ali
Jun 22 2020
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 (b) how many bugs % are due to front / popFront separation? 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? -- 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();"? And why not provide a popAndReturnFront(), and let the user decide based on his/her own actual usage?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)?Use these functions inside a while(!range.empty()) {...} can only introduce more code complexity.(or do we have another function for this)?There are many useful functions in std.range: https://dlang.org/phobos/std_range.html The "take" and "drop" functions may be useful.
Jun 22 2020
On 6/22/20 2:37 PM, mw wrote:On Monday, 22 June 2020 at 20:58:58 UTC, Ali =C3=87ehreli wrote:Others have other explanations for this but my understanding is about=exception safety: If it changed internal state and returned the front=cobject, you would no be able to make a function like popFront() strongly exception safe. (There are ample documentation for this topi=I am not claiming that strong exception safety is the reason for Phobos=20 design. However, knowing what I know, I would use the same primitive=20 operations. It's the same with e.g. C++ as well: !=3D end(), operator*,=20 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=20 strongly exception safe but the reverse is always possible.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(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=20 that was it.And which is more bug-prone for a typical programmer? my gut feeling i=s(b), at least we just saw one in this thread. And -- loop thru a static structure content like a simple array, why we ne=edto worry about exception safe?*If* strong exception guarantee is needed, it doesn't matter whether=20 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(); ..==2E;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=20 popFront().And why not provide a popAndReturnFront(), and let the user decide bas=edon his/her own actual usage?Because if the primitives were empty() and popAndReturnFront(), then it=20 wouldn't be made strongly exception safe. With the current primitives of = empty(), front(), and popFront(), it's possible to implement=20 popAndReturnFront(). I like the following one that I wrote in three=20 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 =3D [ 1, 2, 3 ]; while (true) { auto front =3D range.popAndReturnFront; if (!front.get()) { break; } writeln(front); } }I am not aware of any bugs related to the separation of front() and=20 popFront(). AliAnother 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)?
Jun 22 2020
If you are referring to the next line, not the next n lines, that's a simple `continue;` statement.
Jun 22 2020
On Monday, 22 June 2020 at 20:02:22 UTC, kinke wrote:If you are referring to the next line, not the next n lines, that's a simple `continue;` statement.[Please discard, that'd obviously be skipping the *current* line.]
Jun 22 2020