Skip to content

RFC: define behavior for __setitem__ when the assigned value promotes to the array's dtype #916

Closed
@crusaderky

Description

@crusaderky
Contributor

__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

changed the title [-]Clarification on `__setitem__` and in-place ops type promotion rules[/-] [+]Tighten `__setitem__` and in-place ops type promotion rules[/+] on Mar 25, 2025
crusaderky

crusaderky commented on Mar 25, 2025

@crusaderky
ContributorAuthor

In my opinion, the wording should be changed from

  • 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.

to

  • Setting array values must not affect the data type of self.
  • Behavior must otherwise follow Type Promotion Rules.
  • If it's not possible to respect the rules by just altering the value being set (for example, when setting a int32 value into a int16 array), behavior is undefined.
rgommers

rgommers commented on Mar 25, 2025

@rgommers
Member

That wording change sounds fine to me.

mdhaber

mdhaber commented on Mar 25, 2025

@mdhaber
Contributor

Assuming "promote value to [type]" is unambiguous1, is the last bullet different from:

If value does not promote to self.dtype, behavior is undefined.

?

If so, maybe the three rules can be summarized

value must be promoted to self.dtype according to Type Promotion Rules; if this is not possible, behavior is undefined.

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

  1. leave it alone if value.dtype == self.dtype, otherwise follow arrows from value.dtype to self.dtype

crusaderky

crusaderky commented on Mar 26, 2025

@crusaderky
ContributorAuthor

Or maybe that is only the second and third rule. I suppose the first rule is independent, because it defines what can't happen.

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:

  • Setting array values must not affect the data type of self.
  • value must be promoted to self.dtype according to Type Promotion Rules; if this is not possible, behavior is undefined.
crusaderky

crusaderky commented on Mar 26, 2025

@crusaderky
ContributorAuthor

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.

changed the title [-]Tighten `__setitem__` and in-place ops type promotion rules[/-] [+]RFC: define behavior for `__setitem__` when the assigned value promotes to the array's dtype[/+] on Apr 3, 2025
added
RFCRequest for comments. Feature requests and proposed changes.
on Apr 3, 2025
added this to the v2025 milestone on Apr 3, 2025
kgryte

kgryte commented on Apr 3, 2025

@kgryte
Contributor

To me it feels that this doesn't change the intended expected behaviour and it is just a clarification.

@crusaderky Only the draft for this one, I think.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    RFCRequest for comments. Feature requests and proposed changes.

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

      Development

      Participants

      @rgommers@kgryte@crusaderky@mdhaber

      Issue actions

        RFC: define behavior for `__setitem__` when the assigned value promotes to the array's dtype · Issue #916 · data-apis/array-api