Does exposing a Combine publisher of an actor as a nonisolated property violate the thread-safety of the actor?

159 Views Asked by At

In the following example, the private _valuePublisher has been exposed as a type-erased Publisher through a nonisolated property. Additionally, the current value of the _valuePublisher is also exposed as a nonisolated property. The compiler is happy with this arrangement but I'm not sure about the thread-safety aspect of this especially for the unwrappedValue property. Any thoughts?

final actor MyActor {
    
    private let _valuePublisher = CurrentValueSubject<Int, Never>(0)
    
    nonisolated var valuePublisher: AnyPublisher<Int, Never> {
        _valuePublisher.eraseToAnyPublisher()
    }
    
    nonisolated var unwrappedValue: Int {
        _valuePublisher.value
    }
    
    func updateValue(_ value: Int) {
        _valuePublisher.send(value)
    }
}
1

There are 1 best solutions below

1
Rob On BEST ANSWER

You asked:

Does exposing a Combine publisher of an actor as a nonisolated property violate the thread-safety of the actor?

Technically, this actor has no mutable state and thus presents no thread-safety risk; the risk rests in the referenced CurrentValueSubject.

However, if you give the actor a mutable state (by making the actor’s property a var instead of let) and try to expose that via a non-isolated property, that results in errors, as that would threaten the thread-safety of the actor, itself:

Actor-isolated property '_valuePublisher' can not be referenced from a non-isolated context

E.g.:

enter image description here

In short, in the original code snippet, the actor’s property was immutable, so the potential risk rests in the thread-safety of the referenced class, not in that of the actor.


That having been said, there is a thread-safety issue here.

To have the compiler perform more robust checks, I would advise changing the “Strict Concurrency Checking” setting to “Complete”:

“strict concurrency checking” setting to “complete”

When you do this, it will warn you of the problems:

Non-sendable type 'CurrentValueSubject<Int, Never>' in asynchronous access to actor-isolated property '_valuePublisher' cannot cross actor boundary

E.g.:

compiler warnings