std.range.interfaces : InputRange moveFront

Steven Schveighoffer schveiguy at yahoo.com
Fri Dec 1 18:55:53 UTC 2017


On 12/1/17 1:33 PM, Ali Çehreli wrote:
> On 12/01/2017 07:21 AM, Steven Schveighoffer wrote:
>  > On 12/1/17 4:29 AM, Johan Engelen wrote:
> 
>  >> (Also, I would expect "popFront" to return the element popped, but it
>  >> doesn't, OK...
>  >
>  > pop removes the front element, but if getting the front element is
>  > expensive (say if it's a map with a complex lambda function), you don't
>  > want to execute that just so you can return it to someone who doesn't
>  > care. This is why front and popFront are separate.
> 
> Yet, we're told that compilers are pretty good at eliminating that 
> unused copy especially for function templates where all code is visible.

yes, true. But this is not something to rely on, and it's not always 
possible.

> [I have second thoughts about what I write below. Bear with me...]
> 
> I think the actual reason is one that I learned in C++ circles which I 
> will never forget as I was lurking on comp.lang.c++.moderated as the 
> whole exception safety was discussed, finally solved, and popularized by 
> Herb Sutter.
> 
> So, even thoug exception safety is not a common topic of D community, 
> the real reason for why popFront() does not return the element is for 
> strong exception safety guarantee. Otherwise, it's not possible to 
> recover from a post-blit that may throw. The reason is, popFront() must 
> change the structure of the container *before* the returned object must 
> be copied. When the copying throws, then the element is already lost 
> from the container.

Hm... yes this is a more pressing problem. But I don't know if it has to 
do with exception safety vs. purely implementation concerns. I remember 
discussions about such a wrapper, and a case where it breaks down is byLine.

Once you popFront a byLine range, the element that was at front is now 
possibly invalid (the buffer may be reused). So in order to return the 
line from popFront, you have to store it somewhere. This means 
allocating another buffer to hold the line you just returned. So the 
costs of doing this aren't just that you might do work and just throw it 
away, it's that you have this extra caching problem you didn't have before.

> However, there are two potential solutions that I think of:
> 
> - D could move the element out; so no post-blit would be necessary. 
> However, as we see in moveFront()'s source code, it might have to call a 
> provided moveFront() and that might throw:
> 
>      static if (is(typeof(&r.moveFront)))
>      {
>          return r.moveFront();
>      }

For byLine, this is a non-starter. You can't move the whole thing into 
the return value, as it's referenced data. You'd have to allocate.

> - D has scope(failure) which could revert the container's state but I 
> don't think it's possible for all containers. (And I should have said 
> "ranges".)

Most definitely, ranges never expand.

-Steve


More information about the Digitalmars-d-learn mailing list