www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Why is there no combination of popFront and front to pop? (aka Python

reply Seb <sebi notsharingmy.info> writes:
I am still in the process of learning D - it's a fantastic 
language. Thanks so much!
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.
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.

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? I know there is `takeOne` (which doesn't 
modify the source) and `dropOne` (which will return the resulting 
array after dropping one element).

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!
Feb 16 2016
next sibling parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
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
Feb 16 2016
parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
Sorry, this is the rest of the program: :)

struct S {
     int i;
     static size_t copyCount;

     this(this) {
         ++copyCount;
         if (!(copyCount % 2)) {
             throw new Exception("Failed to copy S");
         }
     }
}

auto next(Range)(ref Range a){
      auto b = a.front;
      a.popFront();
      return b;
}

Ali
Feb 16 2016
prev sibling next sibling parent reply Rikki Cattermole <alphaglosined gmail.com> writes:
On 17/02/16 1:19 PM, Seb wrote:
 I am still in the process of learning D - it's a fantastic language.
 Thanks so much!
 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.
 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.

 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? I
 know there is `takeOne` (which doesn't modify the source) and `dropOne`
 (which will return the resulting array after dropping one element).

 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!
Oh but there is:
Feb 16 2016
parent Marc =?UTF-8?B?U2Now7x0eg==?= <schuetzm gmx.net> writes:
On Wednesday, 17 February 2016 at 01:45:24 UTC, Rikki Cattermole 
wrote:
 On 17/02/16 1:19 PM, Seb wrote:
 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!
Oh but there is:
`moveFront()` doesn't call `popFront()`.
Feb 17 2016
prev sibling parent reply Jonathan M Davis via Digitalmars-d-learn writes:
On Wednesday, February 17, 2016 00:19:09 Seb via Digitalmars-d-learn wrote:
 I am still in the process of learning D - it's a fantastic
 language. Thanks so much!
 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.
 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.

 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? I know there is `takeOne` (which doesn't
 modify the source) and `dropOne` (which will return the resulting
 array after dropping one element).

 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!
As far as defining next on a range goes, there are some cases where it would be more efficient to combine them into one function, but you definitely need them separate for a lot of use cases, and in previous discussions on it, it was deemed not worth having an additional function - on that in most cases is redundant functionality-wise. Another reason is that having next would frequently require caching the front value, which isn't necessarily desirable, and for some ranges (e.g. the result of byLine), front is reused such that calling popFront overwrites front, and next fundamentally wouldn't work in that case (though such ranges often don't play well with many algorithms anyway - about all they're good for is foreach loops - which is why byLineCopy was introduced). So, if we were going to have next on a ranges, we'd need another trait to query for them - e.g. hasNext - and it would complicate ranges further for marginal benefit. As for having a free function like you're showing, we could definitely do that. I expect that the main reason that it's not there is that it does so little that it probably wouldn't be deemed worth adding, but I don't know. Also, in my experience, a lot of range-based code doesn't actually put a popFront right next to a call to front, so it wouldn't help a lot of range-based code anyway (though I'm sure that it would make some range-based code simpler). Feel free to create a pull request to add next. I don't know if it would be accepted or not. I suspect that it mainly comes down to whether such a simple function would be deemed worth adding. On some level, it is a usability improvement, but in theory, we'd prefer to be adding functions to Phobos which add real value rather than simple wrappers that do basic stuff that anyone can easily do. So, it may be accepted as a usability improvement, or it may be rejected on the grounds that it's too simple to be worth it. You won't know if you don't try though. - Jonathan M Davis
Feb 17 2016
parent reply Seb <seb wilzba.ch> writes:
On Wednesday, 17 February 2016 at 11:30:40 UTC, Jonathan M Davis 
wrote:
 Feel free to create a pull request to add next. I don't know if 
 it would be accepted or not. I suspect that it mainly comes 
 down to whether such a simple function would be deemed worth 
 adding. On some level, it is a usability improvement, but in 
 theory, we'd prefer to be adding functions to Phobos which add 
 real value rather than simple wrappers that do basic stuff that 
 anyone can easily do. So, it may be accepted as a usability 
 improvement, or it may be rejected on the grounds that it's too 
 simple to be worth it. You won't know if you don't try though.

 - Jonathan M Davis
Thanks a lot to you all for your input! It helped me to understand D more :) My use case is really about having `pop{Front,Back}` which returns the popped element. I do understand that the current API design is a lot more flexible and better [1] and there's no objection at all from my side. However on the other side we learn the stack syntax with return at university (it's even on wikipedia [2]) and thus I am a friend of such a syntax: auto myFile = ["<crazy header>","1","2"]; // cut off the header myFile.next.writeln; // do sth with the body myFile.map!(to!int).map!"a + 1".map!(to!string).joiner(",").writeln; Anyways I will try my best to submit a PR and we can continue to discuss pros/cons there - imho it's an excellent learning task :) [1] https://stackoverflow.com/questions/12206242/store-results-of-stdstack-pop-method-into-a-variable [2] https://en.wikipedia.org/wiki/Stack_(abstract_data_type)
Feb 18 2016
next sibling parent Seb <seb wilzba.ch> writes:
On Thursday, 18 February 2016 at 13:04:09 UTC, Seb wrote:
 Anyways I will try my best to submit a PR and we can continue 
 to discuss pros/cons there - imho it's an excellent learning 
 task :)
Update: Yeah I submitted my first PR to phobos: https://github.com/D-Programming-Language/phobos/pull/4010
Feb 18 2016
prev sibling parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 02/18/2016 05:04 AM, Seb wrote:

 However on the other side we learn the stack syntax with return at
 university
You must have seen it in the context of reference types, no? There is no problem in languages that don't have value types. The problem is with the final copying of the value to the caller's context. If that operation throws, then the function is not strongly exception safe.
 (it's even on wikipedia [2]) and thus I am a friend of such a
 syntax:
 [2] https://en.wikipedia.org/wiki/Stack_(abstract_data_type)
That Wikipedia article has no mention of "exception". Dismissed... :) Exception safety involves "cohesion". That's the term Herb Sutter had used in the context of C++ exception safety. One of his guidelines: "Prefer cohesion. Always endeavor to give each piece of code—each module, each class, each function—a single, well-defined responsibility." The next() you are proposing is inferior to front() and popFront() because it mixes the two concerns: access and mutation. I guess it would be acceptable if next() required that the copy operation on the elements were nothrow. I think then it would be safe. Ali
Feb 18 2016