Why is there no combination of popFront and front to pop? (aka Python `next`)

Ali Çehreli via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Tue Feb 16 16:57:14 PST 2016


On 02/16/2016 04:19 PM, Seb wrote:

 > However there is one thing that I came by which I think is a bit
 > annoying and could be easily solved - there seems to be no way to
 > combine `front` and `popFront` in one call even tough this use case
 > seems quite frequently to me.

Although it seems natural, such a function would be less desirable 
because of its side-effect.

 > At least I am used from Python to use next(<some lazy loaded stream>) to
 > get its next element and I desperately searched for similar method in D.

There are already convenient methods that achieve the same:

     foreach (e; range) {
         // ...
     }

     range.each!(/* ... */)

     range.map!(/* ... */)

 > I know that I can use `.front` and `popFront`, but why isn't there `pop`
 > or `next` that returns the first element from the lazy loaded range?

When a library separates those two functions, it is usually to provide 
strong exception-safety guarantee.

 > In any case such a next method would be very easy to implement (see
 > below) and thus I am wondering why it isn't part of phobos?
 >
 > ```
 > auto next(Range)(ref Range a){
 >      auto b = a.front;
 >      a.popFront();
 >      return b;
 > }
 >
 > ````
 >
 > Thanks for your input!

1) So, the idea is that if an exception is thrown when coping 'b' to the 
caller's context, then 'a' has already been modified by popFront(). That 
makes the function is not strongly-exception-safe.

Given that it's so easy to write, the programmer can chose to take 
advantage of such a function if that much guarantee is not needed. :)

2) Another reason is that 'next' cannot work with rvalue ranges because 
rvalues cannot be bound to ref function parameters in D. The following 
code demonstrates both cases:

import std.stdio;
import std.range;
import std.algorithm;

void main() {

     auto r = [ S(0), S(1), S(2) ];

     try {
         writeln(r.next);

     } catch (Exception e) {
         writeln("Ok, something bad happened; let's move on...");
         writefln(`(The error was: "%s".)`, e.msg);
     }

     // 1) Oops. Where is the first object?
     assert( !r.equal([ S(0), S(1), S(2) ]));

     // 2) Compilation ERROR:
     // writeln(iota(3).next);
}

Ali



More information about the Digitalmars-d-learn mailing list