Using 'filter' on an array of actors

Hi everyone,

I have a function that filters an array of Actors:

actor Entity {
    // other stuff
    var state: State {
        // determine state
    }
}

actor World {
    // other stuff
    let entities: [Entity]

    func getActiveEntities() async -> [Entity] {
        entities.filter { $0.state == .active }
    }
}

This doesn't compile because of the following error: Actor-isolated property 'state' can not be referenced from a non-isolated context.

My question is, how can I use the typical collection functions like filter, first, map, reduce when iterating over a collection of actors?

I don't know if there is something direct to solve this… but you might be able to use AsyncSyncSequence to transform entities to an AsyncSequence that can then accept the async version of filter. And then try to use the Collection Initializers to await on a regular Array.

1 Like

that's an interesting approach. I'm gonna give this a try!

1 Like

OK. First off, I like this approach way more than the CoPilot suggestion to do:

var activeEntities = [Entity]()
for entity in entities {
    if await entity.state == .active {
        activeEntities.append(entity)
    }
}
return activeEntities

There is something interesting about using Async Sequences this way. After some more filtering, this is the type I ended up with:
AsyncFilterSequence<AsyncFilterSequence<AsyncFilterSequence<AsyncSyncSequence<[Entity]>>>>

This isn't really what's stopping me now though.

I would like to sort the array, based on distance from a specific entity, to get the closest one to the player. The sort method isn't available though, however min is.

But this gives this warning message, that I can't really explain in this context:
Passing argument of non-sendable type '(AsyncFilterSequence<AsyncFilterSequence<AsyncFilterSequence<AsyncSyncSequence<[Entity]>>>>.Element, AsyncFilterSequence<AsyncFilterSequence<AsyncFilterSequence<AsyncSyncSequence<[Entity]>>>>.Element) async -> Bool' (aka '(Entity, Entity) async -> Bool') outside of actor-isolated context may introduce data races
I would expect that min would work similar to filter, but apparently it does not.

Is there a tutorial/book somewhere that explains these use cases some more? I.e. working with collections of actors?

1 Like

Ah, fixed the last warning. Had to mark the closure that was passed in to ‘min’ as ‘@Sendable’.

Regardless, I am truly impressed with the concurrency checker in Swift. Never have I felt more confident with async and multi threaded code.

2 Likes