-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
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
RFC: Make any
and all
always short-circuit
#19543
Conversation
089e5a9
to
83071d0
Compare
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 enjoy that this code is much simpler. Honestly, I think I'd much rather move all of our reduction code back to this sort of simple definition unless there's a really compelling reason. It's gotten pretty hairy and out of control.
This code here could be removed also: base/reduce.jl#L561-L569 |
Good catch, @fcard, thanks! |
These changes make me wonder whether Side note: The 32-bit Windows build failure looks like one of those intermittent Git issues |
@ararslan Do you mean that as " |
eltype(itr) <: Bool ? | ||
mapreduce_sc_impl(f, |, itr) : | ||
reduce(or_bool_only, false, itr) | ||
function any(f::Predicate, itr) |
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.
You could also change mapreduce_sc_impl
in terms of these for now and leave the cleaning of the rest of the reduce code for another PR. That is
mapreduce_sc_impl(f, ::typeof(|), itr) = any(f, itr)
mapreduce_sc_impl(f, ::typeof(&), itr) = all(f, itr)
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 looks as though if I change mapreduce
to do that directly, there's no need for any of the other mapreduce_*sc*
functions.
@fcard I mean that—assuming I'm following all the logic correctly—the
groan 🙂 |
As an aside, I just realized that in the linked issue, the reason why the generator wasn't being short circuited was because the |
The only thing that short-circuits other than function mapreduce{R}(f::PureFunction, op::ShortCircuiting{R}, init::R, itr)
local r::R = init
local terminal = terminal_values(op,R)
for x in itr
r = op(r, f(x))
r in terminal && return r
end
return r
end
...But that's not happening any time soon is it? Even if it eventually becomes possible and is something wanted in Base (it could also go in a package), it's not going to reuse any of the code here. (my original code looked a bit more like this, but really I shouldn't have based it in a dream so far in the future) What I am trying to say is that unless anyone cares about short-circuiting ... Goodbye, my beautiful children. I hope you served your purpose well 😢> This is the third or fourth reason that I give for making the code like this, but they were all true in different ways:
Sorry if I am being long-winded and over-explaining myself, I am trying to cope, it was my first big contribution to anything... But I still wholeheartedly approve this simplification. |
@fcard You have every reason to be proud of your children, for they have served valiantly. You've made an invaluable contribution to Julia through them, and they will live eternally in Julia versions past. @StefanKarpinski Would you mind taking another look at this? It's changed a fair bit since you submitted your review. Edit: |
mapreduce(f, op::ShortCircuiting, n::Number) = n | ||
mapreduce(f, op::ShortCircuiting, itr::AbstractArray) = mapreduce_sc(f,op,itr) | ||
mapreduce(f, op::ShortCircuiting, itr::Any) = mapreduce_sc(f,op,itr) | ||
mapreduce(f, op::Union{typeof(&), typeof(|)}, n::Number) = n |
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 actually should be
mapreduce(f, op::Union{typeof(&), typeof(|)}, n::Number) = f(n)
^^^^
I just now noticed this dumdum mistake of mine (thankfully calling mapreduce(f, rand([&,|]), x::Number)
instead of f(x)
never took off, it had all the potential to be the new x |> f
)
But maybe you should just remove all short-circuiting mapreduce
methods all together for now, since the only thing using Predicate is any
/all
and nothing else will short-circuit. You could also test to see if thePredicate
thing still has any performance advantages and remove that as well if it doesn't.
Or you could just focus on the any
/all
part and leave me to clean up after my own mess in a followup PR, all valid options in my book :P
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.
Haha yeah, I noticed the f(n)
thing as I was going through here. I've simplified things in this PR but if people end up wanting me to undo stuff here, I'll leave the rest to you. 😉
Can't we get rid of Presently, |
@martinholters Sounds excellent to me! I'll make those changes later today. We should probably run Nanosoldier afterward as well, just in case. |
e0e7fe1
to
e59a277
Compare
@nanosoldier |
Your benchmark job has completed - possible performance regressions were detected. A full report can be found here. cc @jrevels |
Nanosoldier benchmarks on the merge commit if I recall correctly. However, these benchmarks have popped up before so I think they are a bit noisy. |
That's what I was thinking but I'm never sure...
Quite possibly, though I thought I had rebased from master before the most recent push. And if Nanosoldier benchmarks on the merge commit that should make it irrelevant anyway. It this okay then? Also: Does this warrant a news item? It changes the behavior such that |
yes, should go in news |
And gone in NEWS it has. 🙂 Thanks, @tkelman. |
e5a4417
to
6a346b5
Compare
@@ -74,6 +74,10 @@ Library improvements | |||
|
|||
* New `titlecase` function, which capitalizes the first character of each word within a string ([#19469]). | |||
|
|||
* `any` and `all` now always short-circuit, and `mapreduce` never short-circuits ([#19543]). |
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.
Could also mention reduce
here, since it is equally affected by the change.
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.
Good call, added. Thanks!
or_bool_only(a::Bool, b::Bool) = a|b | ||
and_bool_only(a, b) = nonboolean_error(:all, :&) | ||
and_bool_only(a::Bool, b::Bool) = a&b | ||
|
||
""" | ||
any(p, itr) -> Bool |
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.
Maybe mention short-circuiting behaviour in the docs?
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.
with an example, e.g.:
any(i -> (println(i); i > 3), 1:10)
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.
Done. Look okay? Thanks!
cb2532a
to
df560dd
Compare
@@ -524,6 +476,7 @@ end | |||
any(itr) -> Bool | |||
|
|||
Test whether any elements of a boolean collection are `true`. | |||
Not all items in `itr` will be visited if a `true` value is found. |
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.
maybe "Returns true
as soon as the first true
value is found in itr
(short circuiting)." ?
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 mix of imperative ("test whether") and non-imperative ("returns true") seems a little odd to me but maybe it's fine. How about something like
Test whether any elements of a boolean collection are
true
, returningtrue
as soon as the firsttrue
value initr
is encountered (short-circuiting).
?
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.
Cool, went with that then. Thanks!
I just now realized that |
Is this good to go then? |
|
Kind of? Agreed regarding those changes being a separate PR, if they're necessary. |
We should probably put back Predicate and ShortCircuiting as non-exported deprecated bindings, since removing them broke several packages. |
If you can point me to which packages in particular broke I can submit PRs. I've done so for Lazy.jl and ColorVectorSpace.jl so far. |
Grepping registered packages, it looks like ColorVectorSpace was the only user of ShortCircuiting, and aside from Lazy the only package that uses |
Cool, I just submitted a PR to DistributedArrays, so I think I've got everything covered now. |
Fixes #19151
This implements @JeffBezanson's suggested simplification. With this change,
any
andall
will short circuit in all circumstances. Currently they short circuit for arrays (we even have a test for that) but not for generators.