I am not sure why all the code below compiles, particularly the class with a mutable state.
Environment
Xcode command line project
Xcode Version 14.0 beta 3 (14A5270f))
macOS 13.0 Beta (22A5295i)
Questions
Do all value types conform to Sendable by default?
Why is a class with a mutable state allowed to be assigned to a Sendable?
Or am I missing something?
Code
struct S {}
enum E { case ok }
actor A {}
class Engine {}
class Car {
var engine: Engine
init(engine: Engine) {
self.engine = engine
}
}
var c1 = Car(engine: Engine()) //class with a mutable state
let s1: Sendable = S()
let s2: Sendable = E.ok
let s3: Sendable = A()
let s4: Sendable = c1 //Why is this allowed?
That's weird and afaik should not happen.
A quick check with fresh Xcode 13.4.1 iOS and macOS playgrounds gives the expected error message Value of type 'Car' does not conform to specified type 'Sendable'.
I don't have a newer Xcode handy atm to test, but perhaps this is a bug you should report? I'd be very surprised if there was a recent change that actually gives that class implicit conformance as I don't think that's even feasible...
It could also be that it is related to your previous post (I just noticed it's you), in that due to this being a command line project it "overlooks" this also concurrency related error, but then I'm surprised it catches on in a simple playground this time...
It depends a bit, the Swift 5.7 version of TSPL has a new section about this, specifically the very last paragraph explains this via an example:
Because TemperatureReading is a structure that has only sendable properties, and the structure isn’t marked public or @usableFromInline , it’s implicitly sendable. Here’s a version of the structure where conformance to the Sendable protocol is implied:
In short, if your type has no mutable properties or if all its mutable properties conform to Sendableand it's neither marked as public or @usableFromInlinethenSendable conformance is implicit.
For your initial example that means that S, E, and A are implicitly Sendable.
I guess the main rationale for allowing this was that value types specifically (but probably often enough also reference types with only let properties) were used by people to cross thread/queue boundaries already in existing code (if you ever had to read something from a Core Data stack in a background queue and then needed to pass it to the UI thread without shooting yourself in the foot you had to basically come up with something like a helper type for that reason).
It would suck if all your code now needed to adopt Sendable explicitly although you were already a good developer taking care of this, so I personally welcome that even if it looks weird when you come at it from the other direction.
This is intentional—most warnings about Sendable were backed out because they are too noisy:
You should re-enable the warnings explicitly if you want them:
If you compile your test example with -warn-concurrency enabled, you will be warned that Car does not conform to Sendable, as expected.
To check it out, I put your reduced example from the GitHub bug in a file named “test.swift”, and on the command line I ran:
swiftc test.swift
# No diagnostic output, compiles as expected
swiftc -Xfrontend -warn-concurrency test.swift
test.swift:10:19: warning: type 'Car' does not conform to the 'Sendable' protocol
let s: Sendable = car
^
test.swift:2:7: note: class 'Car' does not conform to the 'Sendable' protocol
class Car {
^
I am able to see the warning after turning on the other swift flags (-Xfrontend -warn-concurrency -Xfrontend -enable-actor-data-race-checks)
From Sendable-related warnings (SE-0302) backed out of Swift 5.6, it seems that they would continue to refine for Swift 5.7, so is the issue that I pointed out worth the review? (should I leave the bug open for it to be considered or should I close the bug?)