You can. But why would you want to do this?
Let's start with the "can" part:
Actually you don't care if Element
is Codable
, because you are not coding individual elements, only the entire set. So actually you need where Self: Codable
constraint. And for ClosuredRange
that's the same constraint. So now you can move this code as an extension to a dummy protocol:
protocol RawRepresentableThroughCodable: RawRepresentable, Codable {}
extension Set: RawRepresentableThroughCodable {}
extension ClosedRange: RawRepresentableThroughCodable {}
extension RawRepresentableThroughCodable {
public typealias RawValue = String
public init?(rawValue: RawValue) {
...
}
public var rawValue: RawValue {
...
}
}
Now the why part.
First of all, you adding so-called "retroactive conformance" - you are conforming type that you don't own to the protocol that you don't own, so probably you are doing someone else's job, which can lead to a mess. You can read more here - swift-evolution/proposals/0364-retroactive-conformance-warning.md at main · swiftlang/swift-evolution · GitHub.
This is a red flag, but probably more a symptom than a root cause. I think the root cause is that you are trying to use RawRepresentable
for this.
Technically it works - it allows to always convert something to a string and sometimes convert it from a string. But still RawRepresentable
was designed for a different purpose.
With a RawRepresentable
type, you can switch back and forth between a custom type and an associated RawValue
type without losing the value of the original RawRepresentable
type. Using the raw value of a conforming type streamlines interoperation with Objective-C and legacy APIs and simplifies conformance to other protocols, such as Equatable
, Comparable
, and Hashable
.
The RawRepresentable
protocol is seen mainly in two categories of types: enumerations with raw value types and option sets.
Typically rawValue
is a cheap O(1) operation to get the value which is literally stored inside.
I'm not sure how this conformance would affect Objective-C interoperation, but know that "simplifies conformance to other protocols" can cause you some troubles.
There the following extensions in the standard library:
extension RawRepresentable where Self : Encodable, Self.RawValue == String {
public func encode(to encoder: Encoder) throws
}
extension RawRepresentable where Self : Decodable, Self.RawValue == String {
public init(from decoder: Decoder) throws
}
With your conformance you make this functions eligible for Set
and ClosedRange
. If they end up being used as an implementation for Codable
, they will call rawValue
/init?(rawValue:)
inside them, leading to infinite recursion.
I would suggest to use a custom protocol instead of RawRepresentable
. Would something like this work for your use case?
protocol StringRepresentable {
init?(stringRepresentation: String)
var stringRepresentation: String { get }
}