Actor property is treated as nonisolated from within module but treated as isolated from outside module

I the below a known bug? Or it is expected behavior? It seems like a bug to me, but maybe I'm wrong.

// ModuleA

public actor Foo {
    public let bar: Int = 7
}
// ModuleB

import ModuleA

func demo (foo: Foo) {
    print(foo.bar) // Error: Actor-isolated property 'someNumber' can not be referenced from a non-isolated context
}

If I move demo(foo:) to ModuleA then it compiles.

…with full concurrency warnings turned on?

I'm not sure - I'm using Xcode 14.2 basically as it comes out of the box. I haven't deliberately modified anything like that. I get (and avoid) plenty of concurrency warnings, so they're certainly not turned all the way off.

This is allowed by SE-0306:

First, a cross-actor reference to immutable state is allowed from anywhere in the same module as the actor is defined because, once initialized, that state can never be modified (either from inside the actor or outside it), so there are no data races by definition.

We have to disallow it across modules because we don’t publicly expose the fact that a read-only piece of state is a let as opposed to a computed var or private(set) var.

2 Likes

But evidently we do publicly expose if I put a nonisolated on the property, because that allows the function to compile inside of ModuleB. Couldn't we publicly mark let properties as nonisolated as if they were explicitly marked as such, but just not requiring the library developer to write a redundant word?

Yes, nonisolated is part of the (public) API contract for your type. Making let imply nonisolated means that it wouldn’t be possible to change a let to later be nonisolated and/or mutable in a source-compatible way. There’s further discussion in the alternatives considered section here.

1 Like