June 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)?


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

Use these functions inside a while(!range.empty()) {...} can only introduce more code complexity.

June 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: [...]
>> >    auto line = range.front;
>> >    range.popFront;  // pop immediately
> [...]
>
> 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").

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?"




June 22, 2020
On Monday, 22 June 2020 at 21:27:12 UTC, Steven Schveighoffer wrote:
>>     auto line = range.front;
>>     range.popFront;  // pop immediately
>
> This is a bad idea, once you popFront, the original front is possibly invalid (and technically is the case for byLine).

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.

June 22, 2020
On 6/22/20 2:37 PM, mw wrote:

> 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

I am not claiming that strong exception safety is the reason for Phobos design. However, knowing what I know, I would use the same primitive operations. It's the same with e.g. C++ as well: != end(), operator*, 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 strongly exception safe but the reverse is always possible.

> (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 that was it.

> 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?

*If* strong exception guarantee is needed, it doesn't matter whether 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(); ...;
> 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 popFront().

> And why not provide a popAndReturnFront(), and let the user decide based
> on his/her own actual usage?

Because if the primitives were empty() and popAndReturnFront(), then it wouldn't be made strongly exception safe. With the current primitives of empty(), front(), and popFront(), it's possible to implement popAndReturnFront(). I like the following one that I wrote in three 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 = [ 1, 2, 3 ];
  while (true) {
    auto front = range.popAndReturnFront;
    if (!front.get()) {
      break;
    }
    writeln(front);
  }
}

>> 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)?

I am not aware of any bugs related to the separation of front() and popFront().

Ali


1 2
Next ›   Last »