Skip to content

Comments

Fix issue 17019: each should be usable with parallel (and behave like foreach)#4990

Merged
dlang-bot merged 1 commit intodlang:masterfrom
wilzbach:fix-15357-each-foreach
Aug 14, 2018
Merged

Fix issue 17019: each should be usable with parallel (and behave like foreach)#4990
dlang-bot merged 1 commit intodlang:masterfrom
wilzbach:fix-15357-each-foreach

Conversation

@wilzbach
Copy link
Contributor

The following test fails:

unittest
{
    import std.algorithm.iteration : each, sum;
    import std.parallelism : parallel;
    import std.range : iota;

    auto logsIndex = new int[10];
    parallel(logsIndex).each!((i, ref e) => e += i);
    assert(logsIndex.sum == 10.iota.sum);
}

while it passes without parallel:

unittest
{
    import std.algorithm.iteration : each, sum;
    import std.parallelism : parallel;
    import std.range : iota;

    auto logsIndex = new int[10];
    logsIndex.each!((i, ref e) => e += i);
    assert(logsIndex.sum == 10.iota.sum);
}

of course the foreach alternative works as well

unittest
{
    import std.algorithm.iteration : sum;
    import std.parallelism : parallel;
    import std.range : iota;

    auto logsIndex = new int[10];
    foreach (i, ref e; parallel(logsIndex))
        e += i;
    assert(logsIndex.sum == 10.iota.sum);
}

(I also added more tests, which should hopefully help to cover more edge cases)

@dlang-bot
Copy link
Contributor

dlang-bot commented Dec 23, 2016

Thanks for your pull request, @wilzbach!

Bugzilla references

Auto-close Bugzilla Severity Description
17019 enhancement std.algorithm.iteration.each should be usable with parallel

Testing this PR locally

If 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#4990"

@wilzbach wilzbach force-pushed the fix-15357-each-foreach branch 2 times, most recently from ea4cc19 to 97a66cc Compare December 23, 2016 22:48
Copy link
Member

@PetarKirov PetarKirov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall LGTM, just some minor comments below:

foreach (ref a, ref b; r)
cast(void)binaryFun!BinaryArgs(a, b);
}
else // static if (isForeachUnaryWithIndexIterable!Iterable)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you want, you can change the static if to a static assert and move it into the else block.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh I opted for this because it was used like this before. I prefer static assert as well :)

debug(each) pragma(msg, "Using foreach for ", Iterable.stringof);
static if (isForeachUnaryIterable!Iterable)
{
debug(each) pragma(msg, "unary");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this can be removed, now that you have debugged the issue ;)

foreach (ref e; r)
{
cast(void)unaryFun!pred(e);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit/personal preference: curly braces are not needed for simple singe statement blocks.

/// each should work with index
@safe unittest
{
import std.range : iota, lockstep;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you also need to import sum, even though it's in same module, so the unittest can be run in the online documentation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

even though it's in same module, so the unittest can be run in the online documentation.

Luckily only external dependencies (e.g. global imports), it's fairly trivial to a import x.y.x and we do so:

https://github.com/dlang/dlang.org/blob/master/js/run_examples.js#L29

The automatic tests extractor which is partially enabled for Phobos does this as well and will warn if someone tries to sneak public tests in that aren't runnable ;-)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! LGTM then.

}

// #15357: `each` should behave similar to foreach
/// each should work with index
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since it's a ddoc-ed example, "each works with iterable objects which provide an index variable, along with each element", or sth. like that would be more appropriate.

assert(arrA.sum == 0);
assert(arrB.sum == 4);

/// three ref parameters
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: use either numbers or words on both places for consistency.

parallel(logs).each!((ref e) => e += 1);
assert(logs.sum == 10);

auto logsIndex = new int[10];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: s/logs/arr/ (logs sounds confusing).

@wilzbach wilzbach force-pushed the fix-15357-each-foreach branch from 7a61f31 to 7273b50 Compare December 25, 2016 08:09
foreach (ref i, ref a; r)
cast(void)binaryFun!BinaryArgs(i, a);
foreach (ref a, ref b; r)
cast(void)binaryFun!BinaryArgs(a, b);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rationale for changing the parameter names?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Strange, yes, but you can't be perfect. I think we should pull.

Copy link
Contributor Author

@wilzbach wilzbach Feb 16, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To symbolize that it's a binary iteration with two elements - i is usually used as designated variable for the loop index.
The idea was to make it similar to std.functional.binaryFun.

Moreover, the private function isForeachBinaryIterable got renamed to isForeachUnaryWithIndexIterable (above) for which the loop variable names are kept.

Copy link
Contributor

@dukc dukc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

each should be usable with everything foreach is with, yes. If only language makes it possible.

More than enough unittests are provided and everything passes. We should pull it.

@wilzbach wilzbach force-pushed the fix-15357-each-foreach branch from 7273b50 to f145959 Compare February 16, 2017 01:51
@wilzbach
Copy link
Contributor Author

(rebased to latest upstream/master)

@wilzbach wilzbach force-pushed the fix-15357-each-foreach branch 2 times, most recently from 343b08b to e898090 Compare February 22, 2017 05:58
@wilzbach
Copy link
Contributor Author

That's weird. It seems for Windows this creates a cyclic dependency:

object.Error@src\rt\minfo.d(378): Cyclic dependency between module std.internal.math.biguintcore and std.parallelism
std.internal.math.biguintcore* ->
std.traits ->
std.algorithm.iteration ->
std.parallelism* ->
std.algorithm.iteration ->
std.bigint ->
std.internal.math.biguintcore*

CC @schveiguy any easy trick to workaround this?

@schveiguy
Copy link
Member

@wilzbach I've run into that before. I think it's due to a difference in how the module info is output on non-Windows platforms. I never got around to figuring out why it happens. The cycle is definitely there, and it's not Windows-specific.

How you deal with the cycle is to get rid of the cycle, no easy tricks. If I were to approach it, I'd say try moving the CACHELIMIT variable and its initialization into its own file. That should break the cycle, since it only depends on druntime, so you can't have a cycle back to Phobos through core.cpuid.

@schveiguy
Copy link
Member

I've run into that before

FYI: dlang/druntime#1602 (comment)

@wilzbach
Copy link
Contributor Author

wilzbach commented Feb 7, 2018

Rebased to master. I have good hopes that this finally passes the testsuite as there was quite some work to get rid of the shared module constructors...

@dlang dlang deleted a comment from codecov-io Feb 7, 2018
@wilzbach
Copy link
Contributor Author

wilzbach commented Feb 7, 2018

Yeah, sometimes time does heal PRs 🎉

image

@n8sh n8sh added the Merge:72h no objection -> merge The PR will be merged if there are no objections raised. label Apr 3, 2018
@wilzbach wilzbach removed the Merge:72h no objection -> merge The PR will be merged if there are no objections raised. label Apr 3, 2018
@wilzbach
Copy link
Contributor Author

wilzbach commented Apr 3, 2018

Yeah, sometimes time does heal PRs tada

Grr... and sometime time does break the PR again.
This time it's a segfault with -dip1000 (which is used to build this module since a few weeks):

Reduced ICE: https://issues.dlang.org/show_bug.cgi?id=18713

@wilzbach
Copy link
Contributor Author

wilzbach commented Jun 6, 2018

Now that we no longer use -dip1000, this passes again:

image

@wilzbach
Copy link
Contributor Author

Can't be more green than now. Ready to move on?

Copy link
Member

@andralex andralex left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice work

@dlang-bot dlang-bot merged commit bb769cf into dlang:master Aug 14, 2018
@wilzbach wilzbach deleted the fix-15357-each-foreach branch August 15, 2018 11:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants