Based on this article by John Sundell I have following struct:
protocol Identifiable {
associatedtype RawIdentifier: Codable, Hashable = String
var id: Identifier<Self> { get }
}
struct Identifier<Value: Identifiable>: Hashable {
let rawValue: Value.RawIdentifier
init(stringLiteral value: Value.RawIdentifier) {
rawValue = value
}
}
extension Identifier: ExpressibleByIntegerLiteral
where Value.RawIdentifier == Int {
typealias IntegerLiteralType = Int
init(integerLiteral value: IntegerLiteralType) {
rawValue = value
}
}
It can be either String or Int. To be able to print it simply(without need to use .rawValue
), I've added following extensions:
extension Identifier: CustomStringConvertible where Value.RawIdentifier == String {
var description: String {
return rawValue
}
}
extension Identifier where Value.RawIdentifier == Int {
var description: String {
return "\(rawValue)"
}
}
The problem is, it works only for extension which conforms to CustomStringConvertible, and the other one is ignored. And I can't add the conformance to the other extension as they would overlap.
print(Identifier<A>(stringLiteral: "string")) // prints "string"
print(Identifier<B>(integerLiteral: 5)) // prints "Identifier<B>(rawValue: 5)"
You could use a single CustomStringConvertible
extension instead of the two you have at the moment, regardless of type:
extension Identifier: CustomStringConvertible {
var description: String {
"\(rawValue)"
}
}
For me this correctly prints "string" then "5" as per your last code example.
This coincidentally is what Sundell does in his open source Identity implementation of Identifiable/Identifier – https://github.com/JohnSundell/Identity/blob/master/Sources/Identity/Identity.swift#L72-L78
Point-Free's 'Tagged' implementation is also worth a look for reference: https://github.com/pointfreeco/swift-tagged/blob/master/Sources/Tagged/Tagged.swift