[Pitch] Transactional observation of values

Hmm. I am seeing a problem where values in the sequence are not always emitted (it can be any non-initial value but it's most annoying when it's the last value).

I'm running the following code using the approach described in my previous comment. In the following code, increment() and end() are called back-to-back and the result seems to be non-deterministic about whether Observed will emit 0 then nil, (in which case the sequence will end as expected) or whether it will emit 0 then 1 and then the sequence will (unexpectedly) never complete.

It looks like end() may be getting called while the iterator is between calls to next()... and in that case there's simply no observation at all? I think there needs to be a way to detect if a change has occurred between calls to next(), otherwise this isn't going to work reliably.

import Observation

actor SomeActor {
    @Observable
    class SomeObservable {
        var value: Int? = 0
    }
    var something = SomeObservable()
    func somethingSequence() -> Observed<Int, Never> {
        return Observed {
            print("Evaluating contents \(self.something.value == nil)")
            return self.something.value
        }
    }
    func increment() {
        print("Incremented")
        something.value = something.value.map { $0 + 1 }
    }
    
    func end() {
        print("Ending")
        something.value = nil
    }
}

let actor = SomeActor()

let task = Task {
    print("Start of task")
    let sequence = await actor.somethingSequence()
    for await value in sequence {
        print("The current value is \(value)")
    }
    print("End of task")
}

try? await Task.sleep(for: .seconds(1))
await actor.increment()
await actor.end()
try? await Task.sleep(for: .seconds(1))
await task.value

print("End of process")
1 Like