Jens
1
Are there any reasons why eg Array, Range and ClosedRange shouldn't conform to LosslessStringConvertible?
Naive implementation
extension Range: LosslessStringConvertible where
Bound: LosslessStringConvertible
{
public init?(_ description: String) {
let c = description.components(separatedBy: "..<")
guard c.count == 2, let lower = Bound(c[0]), let upper = Bound(c[1])
else { return nil }
self = lower ..< upper
}
}
extension ClosedRange: LosslessStringConvertible where
Bound: LosslessStringConvertible
{
public init?(_ description: String) {
let c = description.components(separatedBy: "...")
guard c.count == 2, let lower = Bound(c[0]), let upper = Bound(c[1])
else { return nil }
self = lower ... upper
}
}
extension Array: LosslessStringConvertible where
Element: LosslessStringConvertible
{
public init?(_ description: String) {
self.init()
for oe in description
.dropFirst().dropLast().components(separatedBy: ", ")
{
guard let e = Element(oe) else { return nil }
self.append(e)
}
}
}
dwaite
(David Waite)
2
The issue here is that lossless strings aren’t a text safe encoding - E.g code trying to parse an array of strings wouldn’t know if a comma was emitted by it or one of its Elements
6 Likes
xwu
(Xiaodi Wu)
3
Right, there is no limit on what the lossless string to which a value is converted may contain, so no way to ensure that any delimiter (e.g., commas, "...", etc.) doesn't appear in the lossless string representation of the bound of a range or an element of an array in a way that is distinguishable from the delimiter. It is perfectly valid for me to create a custom type where the lossless string representation of a value is ,,,....
3 Likes
Good question. It is strange, because Array<T: Decodable> can be decoded. For example, Array can be decoded from json string "[1, 2, 3]", So, for now it is possible to init an Array from String, though making it using JsonDecoder. Seems that Array<T: LosslessStringConvertible> should also be LosslessStringConvertible by itself.
jenox
(Christian Schnorr)
5
Of course we can't simply join the lossless string representations of the elements (in the case of Array) with a separator like ,. But we should be able to escape the lossless string representations of the elements, for example by replacing occurrences of \ with \\ and , with \,, and then join those.
Jens
6
Wouldn't that require changing the .description / CustomStringConvertible-conformance of Array or its Element (and [Closed]Range or its Bound)?
I mean, since:
public protocol LosslessStringConvertible : CustomStringConvertible {
/// Instantiates an instance of the conforming type from a string
/// representation.
init?(_ description: String)
}
cukr
7
you would have to change it in any case, because currently Array uses debugDescription of the elements, not description
example with your naive implementation
import Foundation
extension Array: LosslessStringConvertible where
Element: LosslessStringConvertible
{
public init?(_ description: String) {
self.init()
for oe in description
.dropFirst().dropLast().components(separatedBy: ", ")
{
guard let e = Element(oe) else { return nil }
self.append(e)
}
}
}
struct Foo: CustomDebugStringConvertible, LosslessStringConvertible {
init?(_ description: String) {
guard description == "B" else { return nil }
}
init() { }
var debugDescription: String { "A" }
var description: String { "B" }
}
let arr = [Foo()]
print([Foo](arr.description)) // nil
1 Like
Jens
8
Sure, I accepted the explanations of why it wouldn't work, ie that the following is the answer to the question of this thread:
jenox
(Christian Schnorr)
9
My bad, I thought LosslessStringConvertible consisted of an additional string property that we could use without changing the semantics of description and debugDescription.
Jens
10
I wonder why it doesn't / if that wouldn't be better. Ie, how does the benefits of letting LosslessStringConvertible inherit from CustomStringConvertible outweigh any potential confusion / trouble / limitations caused by that entanglement?
Seems to me like LosslessStringConvertible is more "critical" than CustomStringConvertible, yet the former is based on the latter.
CustomStringConvertible's documentation even states that:
Accessing a type’s description property directly or using CustomStringConvertible as a generic constraint is discouraged.