Make each capable of early stopping#5268
Conversation
|
Code is a tad repetitive, ideas welcome on how to simplify. |
each capable of early stopping
std/algorithm/iteration.d
Outdated
|
|
||
| Normally the entire range is iterated. If partial iteration (early stopping) is | ||
| desired, `fun` needs to return a value of type $(REF Flag, | ||
| std.typecons)`!"each"` (`No.each` to continue iteration, or `No.each` to stop |
There was a problem hiding this comment.
What happens if I specify Yes.each ?
std/algorithm/iteration.d
Outdated
|
|
||
| Params: | ||
| pred = predicate to apply to each element of the range | ||
| r = range or iterable over which each iterates |
std/algorithm/iteration.d
Outdated
| iteration). | ||
|
|
||
| Params: | ||
| pred = predicate to apply to each element of the range |
std/algorithm/iteration.d
Outdated
| while (!r.empty) | ||
| { | ||
| cast(void) unaryFun!pred(r.front); | ||
| static if (!is(typeof(unaryFun!fun(r.front)) == Flag!"each")) |
There was a problem hiding this comment.
swap the then and else clauses to eliminate the !
There was a problem hiding this comment.
Nah, then I have a dangling else and need to add gnarly {}
There was a problem hiding this comment.
The ! is a cognitive problem. Negations in general should be avoided. I missed it myself the first time through, and got mildly confused for a moment.
std/algorithm/iteration.d
Outdated
| while (!r.empty) | ||
| { | ||
| cast(void) binaryFun!BinaryArgs(i, r.front); | ||
| static if (!is(typeof(binaryFun!BinaryArgs(i, r.front)) == |
std/algorithm/iteration.d
Outdated
| cast(void) binaryFun!BinaryArgs(i, r.front); | ||
| static if (!is(typeof(binaryFun!BinaryArgs(i, r.front)) == | ||
| Flag!"each")) | ||
| cast(void) binaryFun!BinaryArgs(i, r.front); |
There was a problem hiding this comment.
not sure what the cast(void) is good for
There was a problem hiding this comment.
It was there. Chesterton's fence...
There was a problem hiding this comment.
It's a common stylistic practice in other languages, in some it is required. The function shouldn't be returning a significant value anyway.
There was a problem hiding this comment.
It's required if binaryFun is a strongly pure function and has a return type of void.
There was a problem hiding this comment.
@MetaLang hmmm, yah but in that case it seems the cast precludes a potentially useful warning. This also ties in somehow with @schveiguy's discussion of free.
There was a problem hiding this comment.
Depends on whether you want each to only accept non-strongly-pure functions or not. My first thought is that it's fine because why would you use each if you don't want to do something impure? However, if you want each to be as close in functionality to foreach as possible, then strongly-pure functions should be allowed as it is perfectly acceptable to have a "pure" foreach loop:
foreach (i; [0, 1, 2])
{
//This loop has no side-effects
}
That said, if I understand how strong-pure inference works, this code should not be accepted by the current DMD:
[0, 1, 2].each!((i) {}); //Should not compile
However, this code is accepted by DMD 2.037.2, so it looks like a non-issue (and now makes me wonder why this is accepted). If a problem ever does come up we can deal with it then.
std/algorithm/iteration.d
Outdated
| auto result = Yes.each; | ||
| auto dg(Parameters!(Parameters!(r.opApply)) params) | ||
| { | ||
| static if (!is(typeof(binaryFun!BinaryArgs(i, e)) == Flag!"each")) |
There was a problem hiding this comment.
is(typeof(binaryFun!BinaryArgs(i, e)) == Flag!"each") appears repeatedly. Factor it out and use it to initialize a manifest constant.
There was a problem hiding this comment.
How? Zat iz ze queschiohn.
There was a problem hiding this comment.
enum isEach = is(typeof(binaryFun!BinaryArgs(i, e)) == Flag!"each");
...
static if (isEach)
...
There was a problem hiding this comment.
@WalterBright there is no improvement - essentially this introduces one additional name that is used only once. No?
| (isForeachUnaryIterable!R || isForeachBinaryIterable!R); | ||
|
|
||
| void each(Range)(Range r) | ||
| Flag!"each" each(Range)(Range r) |
There was a problem hiding this comment.
Consider using static if instead of these overloads.
There was a problem hiding this comment.
They don't appear in the docs so choosing one or another is a wash. I preserved the existing structure.
|
What's the use case? |
|
ping @andralex @WalterBright What's needed to get this moving again? |
ddb8863 to
ae5d3ae
Compare
|
Thanks for your pull request, @andralex! Bugzilla referencesYour PR doesn't reference any Bugzilla issue. If your PR contains non-trivial changes, please reference a Bugzilla issue or create a manual changelog. Testing this PR locallyIf you don't have a local development environment setup, you can use Digger to test this PR: dub fetch digger
dub run digger -- build "master + phobos#5268" |
Someone to revive it from the dead and rebase to latest, greatest master. I just did so ;-) |
|
@wilzbach needs another rebase |
b1701ac to
005a391
Compare
| is(typeof((R r) { | ||
| foreach (i, ref a; r) | ||
| cast(void) unaryFun!pred(i, a); | ||
| cast(void) binaryFun!BinaryArgs(i, a); |
| } | ||
| else | ||
| { | ||
| if (unaryFun!fun(r.front) == No.each) return No.each; |
There was a problem hiding this comment.
The braces are required to avoid DScanner's "Mismatched static if. Use 'else static if' here." warning.
Done. I also found a small issue with the newly added |
005a391 to
6ef73fb
Compare
|
@wilzbach did you adopt this PR? If so, how does that work? Thx! |
|
I guess it's legal to merge then! |
|
Ah I still wanted to squash the commits, but I guess it's too late now :/ BTW I realized that it might be nice to highlight this change in the release changelog and submitted a changelog entry for it: #6668 |
Flagto the rescue...