Proposal Link: swift-evolution/0089-rename-string-reflection-init.md at master · apple/swift-evolution · GitHub
The review of "SE-0089: Renaming String.init<T>(_: T)" ran from May 17…23, 2016. The proposal has been *returned for revision* and another round of discussion - the core team would love to see the revised proposal make it into Swift 3.
The community and core team both want to remove this “footgun” from the standard library, where someone could write "String(x)” with the intention of getting a value-preserving conversion to String, but may instead get a potentially lossy and potentially expensive reflection-based conversion to a String. After extensive discussion, the core team recommends that the community consider a somewhat more elaborate design:
- Rename the existing reflection-based "String.init<T>(_: T)” initializer to "String.init<T>(describing: T)” as recommend by the community. This initializer would rarely be invoked in user code directly.
- Introduce a new protocol (for sake of discussion, call it “ValuePreservingStringConvertible") that refines CustomStringConvertible but that adds no new requirements. Conformance to this protocol indicates that the “description” requirement produces a value-preserving representation in String form.
- Introduce a new unlabeled initializer on String: "init<T: ValuePreservingStringConvertible>(_ v: T) { return v.description }". This permits the “String(x)” syntax to be used on all values of types that can be converted to string in a value-preserving way.
- Audit important standard library types (e.g. the integer and floating point types), and make them explicitly conform to ValuePreservingStringConvertible with an explicitly implemented “description” property.
- As a performance optimization, change the implementation of the string literal interpolation syntax to prefer the unlabeled initializer when interpolating a type that is ValuePreservingStringConvertible or that has otherwise has an unlabeled String initializer, but use the "String.init<T>(describing: T)” initializer if not.
The expected advantages of this design are:
- Swift encourages the T(x) syntax for value preserving conversions, and this design ensures that String(x) continues to work for the value preserving cases.
- This ensures that the String(x) syntax does not accidentally fall off a performance cliff by using the extremely-dynamic reflection mechanism unintentionally.
- The preferred “I don’t care how you do it, just convert this value to a string somehow” syntax remains string interpolation syntax. This syntax is efficient in the cases where the String(x) syntax is allowed, but fully general to the other cases where custom convert-to-string code has not been provided.
Some remaining open questions:
- Exactly what types should conform to ValuePreservingStringConvertible. It seems clear that integer, floating point types, and Character can and should conform. What other types should?
- Do we need the ValuePreservingStringConvertible at all, or is the existing CustomStringConvertible enough? We already have a few protocols for handling string convertibility, it would be great to avoid adding another one.
Thank you to Austin Zheng for driving this proposal forward!
-Chris Lattner
Review Manager