-
-
Notifications
You must be signed in to change notification settings - Fork 746
Fix 12564, 14493: add std.range.walkBack to get the last element of an input range #5153
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
8171388 to
d4e066b
Compare
d4e066b to
b6f083c
Compare
| if ((isInputRange!Range || isIterable!Range) && !isInfinite!Range) | ||
| in | ||
| { | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be good to provide another overload which accepts a fallback value returned when the input is empty rather than causing an error
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are at least these options:
- use Nullable
- provide an (
.ifEmpty(value)) method that will yield a range of length 1 with the default value if an empty range is passed in and the otherwise the range unmodified - use
enforceinstead (generally disliked, because exceptions allocate) - provide an overload with a
seed
The best precedent I found is maxElement, so I guess we should follow this then.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See #5154 for further discussion about handling empty ranges.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
orElse yum
| { | ||
| // Rebindable doesn't support all types as of now | ||
| Unqual!(ElementType!Range) last; | ||
| foreach (e; range) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be done without Unqual or Rebindable.
while(!range.empty){
auto element = range.front;
range.popFront();
if(range.empty) return element;
}There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, but unfortunately that is slower:
> ldc -O5 -release -boundscheck=off walkBack.d && ./walkBack
walkBack.foreach = 3 secs, 772 ms, 463 μs, and 6 hnsecs
walkBack.while = 4 secs, 191 ms, 417 μs, and 8 hnsecs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm having issues testing using your code with DMD. As it was, the first while test was consuming the range and subsequent tests failed because the range had been consumed.
I fixed it by preceding each call with auto r = range; and operating on r instead, but this served only to make the while approach dramatically slower while not significantly affecting the performance of the foreach test.
I would've expected that rewriting like so might make their performance more similar, but I'm surprised the compiler wasn't able to optimize the structure to look more like this anyway:
bool empty = range.empty;
while(!empty){
auto element = range.front;
range.popFront();
empty = range.empty;
if(empty) return element;
}@UplinkCoder can you explain what's going on here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the foreachloop should be rewritten to this:
{
typeof(range.front()) elm = range.front;
while(!range.empty)
{
ForeachBody()
range.popFront();
elm = range.front;
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rather this:
{
while(!range.empty)
{
typeof(range.front()) elm = range.front;
ForeachBody()
range.popFront();
}
}
DmitryOlshansky
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Truth be told all of these new names to fill every minor need make my head spin. What's the semantics of something like walkBack - I can't tell at glance.
Yeah, and while this probably is something that folks need occasionally, it doesn't seem like all that great an idea in general given how horribly inefficient it is. As such, if we were to add it, I'd be tempted to argue that something descriptive and ugly like But as the second linked bug report mentions, |
The idea behind the
If this functionality be added, I would argue to stay in the naming scheme as
Two random points:
input.buffer(5).tail(5); |
Oh, now I get it so this is like walkLength. I initially read walkBack as an imperative which sounds more like walk the range backwards. Still sucks I guess as I'd never reach out for that intuitively.
By the same person who absolutely loves filling enhancement requests, sometimes it seems to me that we often overlook an option of WONTFIX. |
…nt of an input range
b6f083c to
787ad9b
Compare
|
Knee-jerk reaction: how does this compare to |
See above for a longer motivation, but in short like |
|
Understood. So we have a range that is input but not forward, and want to advance it through the end to get the last element. What's wrong with |
Nothing - I am closing this and the existing bugs I found as |
|
@wilzbach yes awesome and actually that's a rather clever (ahem) use of |
Sure -> #5227 |
This seems to be a missing functionality (when I bumped into this I found two open issues). It behaves as
walkLength.It got a bit messy because
Rebindableisn't a thing yet (see #4363 for more details).