Skip to content

Arrays of structs do not handle assigning a struct that's already in the array #73

@apple1417

Description

@apple1417

Original report was

# Original saves are [0, 1, 2, 3, 4]

# This version results in obj.SaveGames of [4, 3, 3, 4, 0]
obj.SaveGames = sorted(obj.SaveGames,
                       key=lambda x: x.LastSaveDate,
                       reverse=True)

Slightly more insidiously, this is also equivalent to obj.SaveGames.sort(key=lambda x: x.LastSaveDate, reverse=True), which you might expect to work better.

The root cause is structs being reference types, so when we update the first value in the array we're changing the value of whatever index it got sorted to. This is very unintuitive.

As a workaround, you can make a copy of each struct before assigning them:

obj.SaveGames = sorted((copy.copy(x) for x in obj.SaveGames),
                       key=lambda x: x.LastSaveDate,
                       reverse=True)
obj.SaveGames = copy.deepcopy(sorted(obj.SaveGames,
                              key=lambda x: x.LastSaveDate,
                              reverse=True))

This is a broader problem than just sorting though, any slice assignment might run into it

>>> arr = [1, 2, 3, 4, 5] # really a wrappedarray of structs
>>> arr[2:4] = (arr[3], arr[4], arr[3], 6)
>>> arr # should be
[1, 2, 4, 5, 4, 6, 5]

And then more generally, 2d arrays or arrays of multicast delegates, currently the other two reference types, would also be vulnerable.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions