Writable subscript of actor does not work?

Hi,

I have a problem with calling a subscript on an actor.

Searching on google for "swift actor subscript" only resultls in many hits which state the official phrase from the proposal: "Like other Swift types, actors can have initializers, methods, properties, and subscripts. "

Unfortunately I don't know how to or if it is allowed to have a writable subscript on an actor. The following cody may not be very useful, but demonstrates the problem:

actor SyncArray<Element>{
    private var data:Array<Element>
    
    init(_ data:Array<Element>){
        self.data = data
    }
    
    subscript(_ index:Array<Element>.Index) -> Element {
        get { data[index] }
        set { data[index] = newValue }
    }
}

Task{
    let a = SyncArray([1,2,3,4,5])
    
    
    print(await a[2])
    a[3] = 99  // <--- Actor-isolated subscript 'subscript(_:)' can not be mutated from a non-isolated context
    await a[3] = 99 // <--- No 'async' operations occur within 'await' expression
}

results in the shown errors.

Should this be possible and if yes how?

Sure, a workaround would be to define a setElement function on the actor and call it using await.

This is an intentional “policy” limitation to discourage people from making actor interfaces with fine-grained atomicity. Actors can easily guarantee low-level concurrency-safety on individual accesses, but real programs need high-level safety, where operations that need to run atomically on the actor are not interrupted. Programmers need to actually think “transactionally” and plan out their actor interfaces.

This year’s WWDC talk “Eliminating data races with Swift concurrency” talks about this briefly.

5 Likes