Swift Concurrency Protocol & @MainActor

At this stage, I’m just riffing on different ways to ‘break’ swift concurrency.

I wondered if protocols would provide an opportunity, and indeed they do!

Take this scenario. We have a simple protocol – but the class implements it with an @MainActor annotation.

If you do this all within the main class definition, then you get a warning

However, you can declare conformance in an extension and make it @MainActor
No warning here

Or perhaps more confusingly – you can declare your whole class @MainActor, then just conform ‘normally’ in the extension

– in this last case, I wasn’t sure whether it would actually be treated as an @MainActor variable – but I tested, and indeed it is.

So – we have three ways of conforming to a protocol which _doesn’t_ require @MainActor – but in each case, we have required @MainActor in our implementation

Swift Concurrency will use the MainThread for an instance which it recognises as Bar, and won’t bother for an instance it recognises as Thing

I can see the logic here – but once again, @MainActor isn’t guaranteeing anything. The actual call depends subtly on what kind of thing the compiler recognises.

So – we have three subtly different ways of generating exactly the same code.
One of them generates a compile-time warning, the other two do not.

I generally prefer declaring conformance to a protocol in an extension – I had no idea that meant I would get different compile-time warnings.

Sometimes the method is called on Main – Sometimes not!

    func makeBar() -> Bar {
        return Bar()
    func breakWithProtocol() {
        Task {
            var bar:Bar = await makeBar()
            //The compiler recognises a Bar and insists we call asynchronously
            //It will call on the main thread
            _ = await bar.thing

        Task {
            let thing:Thing = await makeBar()
            //The compiler just sees a Thing here - so it calls directly on a background thread
            _ = thing.thing