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.

[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.

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();
    }

- 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".)

Regardless, separating front() from popFront() is preferable due to cohesion: fewer responsibilities per function, especially such low level ones.

Ali

Reply via email to