Say we have
public struct EVMBridgeMessage<P: Codable> : Codable {
public let Cmd: String
public let Payload: P?
public init(c : String, p: P?) {
self.Cmd = c
self.Payload = p
}
public init(c: String) {
self.Cmd = c
self.Payload = nil
}
}
then in usage we have to do
let msg = try! JSONEncoder().encode(
EVMBridgeMessage(c: CMD_REPORT_CHAIN_HEAD, p: BridgeCmdSendBackChainHeader())
)
but I want to do
let msg = try! JSONEncoder().encode(EVMBridgeMessage(c: CMD_REPORT_CHAIN_HEAD))
but I can't because generic P cannot be inferred, but why it matters anyway, .Payload will be nil.
doing EVMBridgeMessage<Void> doesn't fit the bill either.
thank you
tera
2
Void is not decodable. Try with Int or String.
EVMBridgeMessage<Int>(c: CMD_REPORT_CHAIN_HEAD)
so I just have to give any type even though it will be set to nil anyway?
1 Like
itaiferber
(Itai Ferber)
4
Overall, this doesn't have to do with Codable — this case, stripped down, is equivalent to
struct S<T> {
let p: T?
init(_ p: T? = nil) {
self.p = p
}
}
let s = S() // => ❌ Generic parameter 'T' could not be inferred
In order to be able to instantiate S, the compiler needs to know how to lay out S in memory, and doing so depends on the type of T; it doesn't matter that the value of p will be nil, because the compiler has to reserve enough space for any value of T?, and that must be known at compile time.
In order to create an S, you need to explicitly give T:
let s = S<Int>() // ✅
In your specific case, because you also have a requirement that T: Codable, you will specifically need to pass in a type which is Codable (even if it goes unused).
3 Likes
tera
5
Yes. Or you can do it in a way that doesn't require type when using:
public struct EVMBridgeMessage<P: Codable> : Codable {
public let Cmd: String
public let Payload: P?
public init(c : String, p: P) {
self.Cmd = c
self.Payload = p
}
}
extension EVMBridgeMessage where P == Bool {
public init(c: String) {
self.Cmd = c
self.Payload = nil
}
}
EVMBridgeMessage(c: "hello") // ✅
2 Likes
ah thank you, I like this soln