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.
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?)