-
-
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: Deprecate implicit scalar broadcasting in setindex! #26347
RFC: Deprecate implicit scalar broadcasting in setindex! #26347
Conversation
e472a09
to
a5a8fd6
Compare
Alright, so I hit a fairly major performance snag that is inherent to either of the suggested replacement APIs ( @oschulz had suggested a |
Maybe we can somehow specialize |
I think |
That's a compelling argument for I'd love to implement a special |
7cfbfcd
to
ae186be
Compare
ae186be
to
b2c5372
Compare
Good news! The new optimizer has fixed my performance issues! Running BaseBenchmarks locally with JuliaCI/BaseBenchmarks.jl#195 applied leaves me with just two regressions (with default tuning settings) at the moment:
The other issue here is that I have an ambiguity problem with the |
The current `setindex!` function (the `A[i] = b` syntax) does three very different operations: * Given an index `i` that refers to only one location (scalar indexing), `A[i] = b` modifies `A` in that location to hold `b`. * Given an index `I` that refers to more than one location (non-scalar indexing), `A[I] = b` can mean one of two things: * If `b` is an AbstractArray (multi-value), assign the values it contains to those locations `I` in `A`. That is, essentially, `[A[i] = bᵢ for (i, bᵢ) in zip(I, b)]`. * If `b` is not an AbstractArray (scalar-value), then broadcast its value to every location selected by `I` in `A`. These two different behaviors in the non-scalar indexing case basically make using this function in a generic way impossible. If you want to _always_ set the value `b` to many indices of `A`, you _cannot_ use this syntax because `b` might happen to be an array in some cases, radically changing the meaning of the expression. You need to manually iterate over the indices, using scalar setindex methods. But we now also have the new `broadcast!` syntax, `A[I] .= B`, which uses the usual broadcasting semantics to determine how `B` should fill into the values of `A`. This PR deprecates the implicit broadcasting of scalar values in non-scalar indexing in favor of an explicit `.=` broadcast syntax, leaving multi-value non-scalar indexing intact. This is the _exact opposite_ of PR #24368.
b2c5372
to
8ecfdb4
Compare
@nanosoldier |
Your benchmark job has completed - possible performance regressions were detected. A full report can be found here. cc @ararslan |
Well rebasing this on top of #26891 solved multiple issues. The performance is looking pretty good (I had been seeing 10x regressions before), and I think it's technically no longer breaking. That is, the deprecations will use the correct replacement, but we're splitting a dual behavior into two discrete APIs. If you depend upon this dual behavior, then neither of the static replacements will be correct and replacing it will be more challenging… and we cannot know at the time of the depwarn what other call sites might exist. |
I'll merge this tomorrow barring any further comments here. |
Thanks again, @mbauman ! |
Travis failures were: Linux x86_64 failed due to some httpbin.org issue; macOS was a LLVM build issue. Appveyor was the httpbin.org issue and a timeout. |
Line 158 in b5d4f3c
|
The current
setindex!
function (theA[i] = b
syntax) does three very different operations:i
that refers to only one location (scalar indexing),A[i] = b
modifiesA
in that location to holdb
.I
that refers to more than one location (non-scalar indexing),A[I] = b
can mean one of two things:b
is an AbstractArray (multi-value), assign the values it contains to those locationsI
inA
. That is, essentially,[A[i] = bᵢ for (i, bᵢ) in zip(I, b)]
.b
is not an AbstractArray (scalar-value), then broadcast its value to every location selected byI
inA
.These two different behaviors in the non-scalar indexing case basically make using this function in a generic way impossible. If you want to always set the value
b
to many indices ofA
, you cannot use this syntax becauseb
might happen to be an array in some cases, radically changing the meaning of the expression. You need to manually iterate over the indices, using scalar setindex methods. But we now also have the newbroadcast!
syntax,A[I] .= B
, which uses the usual broadcasting semantics to determine howB
should fill into the values ofA
.This PR deprecates the implicit broadcasting of scalar values in non-scalar indexing in favor of an explicit
.=
broadcast syntax, leaving multi-value non-scalar indexing intact. This is the exact opposite of PR #24368.There are still a few things left to do here, making this still a WIP:
MakeTo be done in a separate PR. Or maybe not.setindex_shape_check
more stringent.= nothing
works.setindex!
methods as eitherfill!
orbroadcast!
specializations (or both — having broadcast fall back to fill forScalar()
styles)