Concurrency question - dealing with variables defined as non-isolated in protocols

I'm trying to sort out some patterns of how to handle various scenarios while working with complete concurrency checking. One of the issues I've hit is the pattern of how I've used CustomStringConvertible and CustomDebugStringConvertible in some places - in particular, on classes.

I can update a class to be isolated to a global actor easily enough, @MainActor being the most common bit spread around. I've been using them to help provide debug logging about their current state, and I can pretty easily see where and why that's an error in Swift 6 mode.

An example-ish bit of code:

@MainActor public final class SomeThing: CustomStringConvertible {
  var internalState: Int
  var description: String {
      "SomeThing[\(internalState)]"
  }
}

immediately emits the error:

Global actor 'MainActor'-isolated property 'description' cannot be used to satisfy nonisolated protocol requirement

I can make an async method that returns a description and use that in my debugging logging calls - and have the same effect, but discard conforming to CustomStringConvertible.

@MainActor
public final class SomeThing {
  var internalState: Int
  var description: String {
    get async {
      "SomeThing[\(internalState)]"
    }
  }
}

But is there a path to make a non-isolated computed property that uses the copies of bits of internal state, all of which are Sendable?

Or I guess, more generally, are there any patterns for how to expose a snapshot-in-time Sendable state that can be accessed by synchronous non-isolated properties, or is it the expected path that we have an async let description = thing.description or let copy = await thing.description with a suspension point to get the copy of the state at that point in time external to the class?

I suspect the answer is there is no path, and that it's kind of the point of all this checking, but I'm not trusting my understanding and intuition as I'm working through this.

4 Likes

It seems to be a case to consider within this pitch:

I couldn't find in the proposal this case covered, which seems a logical addition to me.