(procrastination) should CustomStringConvertible.description include quotation marks?

when implementing a CustomStringConvertible.description for a type that wraps a text token (and whose raw String contents should generally not be used verbatim), do you include the quotation marks? why or why not?

struct ID:Hashable, Sendable, Decodable, 
    ExpressibleByStringLiteral, 
    CustomStringConvertible
{
    let string:String 
    
    var description:String 
    {
    #if NO_QUOTES
        self.string
    #else 
        "'\(self.string)'"
    #endif 
    }
}

If the ID.string property is abc, then perhaps the CustomStringConvertible.description should be ID(string: "abc") or ID("abc") which is most similar to the dynamically-generated string representation of a type that doesn't implement CustomStringConvertible. I generally prefer seeing this consistency in CustomStringConvertible conformances. Another advantage of the aforementioned examples is that they encode the type of the value in the string representation, which is often very useful.

1 Like

Yes, include quotes or some other delimiter. There might be leading or trailing spaces that might otherwise be missed. Even interior spaces might lead to a confusing description depending on the string.

I usually won't, mostly because of LosslessStringConvertible which relies on the description provided by CustomStringConvertible to round-trip with the init?(String) initializer. The quotes are most likely not part of the value, so I think they shouldn't be included.

Please note that you can also conform to CustomDebugStringConvertible if you want to provide nicely formatted information about your type for debugging purposes.

2 Likes

that’s a good point

Furthermore, if you look at _print_unlocked implementation where the string that is effectively printed is generated, you can see that String values are directly rendered, without quotes.

Thus, in your example, I would personally use self.string for description, and I could also conform to CustomDebugStringConvertible (which takes precedence for optional and debugPrint(x)), and use:

var debugDescription: String {
  "ID(\"\(self.string)\")"
}

for example.

But it's mostly a matter of personal taste, and you can use whatever convention makes sense depending on the type and the context.

However, I would personally consider description as a "semi-user-facing" value that may be used for other purposes than "private" debugging (for example for generating a JSON via LosslessStringConvertible, or keying a CoreData entry/SQLite row).