Closed KhaledChehabeddine closed 3 weeks ago
The problem here isn't actually in Factory, This is how Swift Sendability check works, property wrappers are only applied to variables and thus will never be Sendable. Let's take a closer look at your example
import Factory
import Foundation
final class SendableClass: Sendable {
}
extension Container {
var sendableClass: Factory<SendableClass> {
self {
.init()
}
}
}
struct SendableStruct: Sendable {
@Injected(\.sendableClass) private var sendableClass: SendableClass
private let sameSendableClass: SendableClass
init() {
self.sameSendableClass = Container.shared.sendableClass()
}
}
On the books this looks fine, but how about if we update it to this?
import Factory
import Foundation
final class SendableClass: Sendable {
}
extension Container {
var sendableClass: Factory<SendableClass> {
self {
.init()
}
}
}
struct SendableStruct: Sendable {
@Injected(\.sendableClass) private var sendableClass: SendableClass
private let sameSendableClass: SendableClass
init() {
self.sameSendableClass = Container.shared.sendableClass()
}
mutating func doSomething() {
sendableClass = SendableClass()
}
}
Even though you won't do that because this is DI code, Swift has no idea about that, it sees a var and it gets upset because this is no longer Sendable across different threads, as opposed to when you define your properties are let there's no way to update their values because well...they are constants. If we ever get to the point where we allow property wrappers on let declarations (https://forums.swift.org/t/pitch-allow-accessor-macros-on-let-declarations/66684) we'll be allowed to rewrite
@Injected(\.sendableClass) private var sendableClass: SendableClass
to
@Injected(\.sendableClass) private let sendableClass: SendableClass
Which allows it to be really Sendable, until then there's no way to fix this error unless you mark your class @MainActor or actor or something.
Thank you for the helpful response, it seems I misinterpreted the error from Xcode. Unfortunate it was a Swift language limitation, I really enjoyed using @Injected
to help reduce the size of my initializers.
Hello,
First, I want to thank you for releasing version 2.4.0 to allow us to more easily satisfy concurrency errors/warnings when shifting to Xcode 16 and Swift 6. However, I am currently facing an issue when injecting dependencies using the
@Injected
property wrapper. The setup can be configured as follows:Package Dependencies:
Swift Version: 6.0
Issue: When injecting a dependency that conforms to
Sendable
using@Injected
, an error is generated by Xcode with the following message:This is an easy example to replicate the issue:
The example showcases the two ways I inject dependencies throughout my project. If I were to set the property directly in the initializer using the container's
shared
property, the sendable conformance would be satisfied and no error would occur. However, if I were to use the convenient@Injected
property wrapper the error arises.Is it not possible to make
Injected
conform toSendable
if it's typeT
itself also conforms toSendable
similar to how you did with Factory, as shown below:Let me know if any additional information is needed to replicate the issue.
Thank you,
Khaled