-
-
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
What to do about multivalue setindex!? #24086
Comments
Yes, picking whether to repeat or broadcast in these cases has always been a bit of a wart.
💯 |
Could we just make this an error for non-scalar |
Notes from triage: We found it helpful to fully define what the different syntaxes here would possibly mean. Note that this needn't be the same as which behaviors we choose to support, and we particularly don't need to have this all defined by 1.0. Here's what we thought made sense — it's perhaps most clear with an example where the keys aren't just integers:
In other words, we can take the same list in bullet point 3 from my first post and just look at it the other way. It's determining which portions of the syntax you're treating as scalar elements:
So, back to the present: With the current (no-dot) So, let's deprecate that ambiguity. That's point 1 in the above proposed solution. That will allow us to layer in the above semantics if we want them (and as we get to them) as new features in 1.x. This has the further advantage of getting rid of another place we we do weird partial linear indexing stuff. We just need to |
Nice summary, @mbauman. I'm also curious about the plan in the case we do #24019, then it seems that a user might attempt to use
and that this is all non-breaking for v1.x? Or would we need to do something else? Or go straight for dot-getindex in #24019? |
You've figured out my secret plan: if we figure this out for I'm firmly against allowing non-scalar indexing for dictionaries using the same syntax as scalar The key for #24019 is to figure out if we can define construction, iteration, and conversion in a consistent fashion that sets us up to use dictionaries and arrays more similarly. And then, yes, in 1.x we could aim to define |
The work for milestone 1.0 has been addressed in #26347. The remaining tasks are 1.x or 2.0 sorts of things. |
Problem
We have two ways to assign many values to many locations in an array:
In this simple case, both of these do the same thing for any array: assign
A[2] = 4
andA[3] = 5
. But in more complicated cases, both syntaxes are quirky in different ways:setindex!
:A[I...] = X
X
must have the same number of elements as the indicesI
select. Shapes are compared, but singleton dimensions are ignored and the final dimension ofX
is allowed to linearly span multiple indices. IfX
is not a subtype ofAbstractArray
, then the same value is simply broadcast to all indices. Examples:Now, if
I
only selects exactly one index then this syntax always putsX
into that location:This is quirky when you actually want to generically assign a single value to multiple locations… and you don't care about its type! Ref. #22747.
broadcast
:A[I...] .= X
Broadcasting dictates that the shape of the indexing expression and the shape of
X
have exactly the same shape if they have the same number of elements. Absolutely no linear spanning is allowed. All of thesetindex!
examples above are errors except for the scalar1
case. At the same time, though,.=
adds the full set of broadcast features, allowing partial arrays to broadcast across the complete set of indices.Now, if
I
only selects exactly one index, then this syntax is quirky:This special-casing on the element type is attempting to work around awkwardness due to the scalar/nonscalar distinction in number of indices. That is,
A[I] .= 0
modifiesA
ifI
is nonscalar, but it should modify the element ifI
is scalar.Proposed solution
Deprecate
multivaluescalar broadcasting withinsetindex!
in favor of the.=
broadcasting syntax..=
is a very nice, explicit signal that you want to broadcast the values on the RHS.The major issue with this deprecation is all the shape permutations thatsetindex!
supports; I believe the deprecation would be:`A[I...] = X` is deprecated. Use `A[I...] .= reshape(X, indices(view(A, I...)))` instead
This is most painful in the common case whereX
is a one-dimensional linear span over a set of indices that is not linear.After attempting to deprecate multivalue scalar indexing in RFC: Deprecate multi-value non-scalar indexed assignment #24368, we realized that it made way more sense to instead deprecate the scalar broadcasting behaviors of setindex. This was done in RFC: Deprecate implicit scalar broadcasting in setindex! #26347.
Remove the
eltype
special-casing indotview
. If the indices are scalar, then we should always attempt to modify the element. This isbreakingdeprecatable. Deprecate array of arrays special casing in .= #24095In 1.x, we could potentially introduce the syntaxes
A.[I]
andA.[I] .= X
. Those are errors at the moment, so we can choose their exact behaviors later. But, they'd allow us to fully detangle the scalar/nonscalar behaviors if we wished:A[i] = x
: Always setsx
at the scalar indexi
.A[i] .= X
: Always broadcastsX
across the element atA[i]
(always mutatingA[i]
). Note that this doesn't make much sense for nonscalarI
as mutatingA[I]
is mutating an unobservable temporary. We would't be able to change this behavior in 1.x, but we could deprecate it in preparation for 2.0.A.[I] = x
: Assignsx
to every index inI
.A.[I] .= X
: Always broadcastsX
across the indices selected byI
(always mutatingA
).The text was updated successfully, but these errors were encountered: