Description
__setitem__
states:
https://data-apis.org/array-api/2024.12/API_specification/generated/array_api.array.__setitem__.html#array_api.array.__setitem__
Setting array values must not affect the data type of self.
When value is a Python scalar (i.e., int, float, complex, bool), behavior must follow specification guidance on mixing arrays with Python scalars (see Type Promotion Rules).
When value is an array of a different data type than self, how values are cast to the data type of self is implementation defined.
The last line is majorly problematic in my opinion and should be revised.
These use cases are left to the library's discretion:
- setting a float array value into an integer array, e.g.
>>> a = xp.asarray([1], dtype=xp.int64)
>>> a[0] = xp.asarray(1.0)
- setting a signed array value into an unsigned array, e.g.
>>> a = xp.asarray([1], dtype=xp.unt64)
>>> a[0] = xp.asarray(-2, dtype=xp.int8)
- setting an array value with a larger dtype into a smaller dtype of the same kind, e.g.
>>> a = xp.asarray([1], dtype=xp.int8)
>>> a[0] = xp.asarray(2, dtype=xp.int64)
All these use cases are quietly allowed by numpy.
Sanity would dictate for them to be all disallowed, exactly like in binops.
If the last use case is allowed, it also opens the issue of in-place binops (__iadd__
) etc.
Whereas out-of-place binops unambiguously must cast the smaller dtype to the larger one and then perform the operation, what is the correct process for in-place ones, when lhs has smaller dtype than rhs?
lhs[idx] = op(lhs[idx], xp.astype(rhs[idx], lhs.dtype))
or
lhs[idx] = xp.astype(op(lhs[idx], rhs[idx]), lhs.dtype)
which is the same as saying
t = xp.result_type(lhs, rhs)
lhs[idx] = xp.astype(op(xp.astype(lhs[idx], t), xp.astype(rhs[idx], t)), lhs.dtype)
? the output will subtly differ.
Activity
__setitem__
should disallow invalid type promotions data-apis/array-api-strict#136any()
fails when wrapping JAX and PyTorch mdhaber/marray#99[-]Clarification on `__setitem__` and in-place ops type promotion rules[/-][+]Tighten `__setitem__` and in-place ops type promotion rules[/+]crusaderky commentedon Mar 25, 2025
In my opinion, the wording should be changed from
to
rgommers commentedon Mar 25, 2025
That wording change sounds fine to me.
mdhaber commentedon Mar 25, 2025
Assuming "promote
value
to [type]" is unambiguous1, is the last bullet different from:?
If so, maybe the three rules can be summarized
Or maybe that is only the second and third rule. I suppose the first rule is independent, because it defines what can't happen.
Footnotes
leave it alone if
value.dtype == self.dtype
, otherwise follow arrows fromvalue.dtype
toself.dtype
↩crusaderky commentedon Mar 26, 2025
In this case I would favor a little bit of potential redundancy for the sake of clarity.
I like the suggestion to squash lines 2 and 3:
crusaderky commentedon Mar 26, 2025
Should the new wording only affect the draft, or also be backported to previous versions?
To me it feels that this doesn't change the intended expected behaviour and it is just a clarification.
[-]Tighten `__setitem__` and in-place ops type promotion rules[/-][+]RFC: define behavior for `__setitem__` when the assigned value promotes to the array's dtype[/+]kgryte commentedon Apr 3, 2025
@crusaderky Only the draft for this one, I think.
__setitem__
type promotion rules for array values #920docs: clarify `__setitem__` type promotion rules for array values