- Proposal: TBD
- Author: Charlie Monroe
- Status: TBD
- Review manager: TBD
This proposal suggests deprecating string interpolation of Optional in order to prevent unexpected results at run time.
Swift-evolution thread: Proposal: Deprecate optionals in string interpolation
When an optional is used for interpolation, either nil
is inserted, or Optional(value)
. The Optional(value)
is seldom the desired output - the user is usually expecting nil
or value
. The current behavior can lead
to many bugs that are hard to debug.
Example:
let myURL = NSURL(string: "http://www.apple.com/iphone")!
let newURL = NSURL(string: "http://www.apple.com\(myURL.path)/about")
The newURL
variable is unexpectedly nil because the string it's being created from is
http://www.apple.comOptional(/iphone)/about
, and figuring out where the actual bug lies requires extra effort.
When an Optional
is used for string interpolation, the compiler issues a warning. Optional
type would be extended
to include these two members:
func descriptionWithDefaultValue(_ defaultValue: String = "nil")
, which would return eitherdefaultValue
or a String created by callingString(self!)
(depending on the result of proposal SE-0089).var detailedDescription: String
which would return the same value asdebugDescription
does now, i.e. eithernil
orOptional(value)
. Alternative names considered includeoptionalDescription
.
public extension Optional {
/// Returns a description which returns defaultValue for nil and "value" for
/// non-nil values.
public func descriptionWithDefaultValue(_ defaultValue: String = "nil") -> String {
if self == nil {
return defaultValue
} else {
return String(self!)
}
}
/// Returns description that is "nil" for nil value and "Optional(value)" for
/// non-nil values.
public var detailedDescription: String {
return self.debugDescription
}
}
Optional
s used in string interpolations will have to be revised by the user and an automatic Fix-It appending
.descriptionWithDefaultValue()
can be offered.
It was considered simply changing the behavior of string interpolation of to drop the Optional(_)
wrap around
the value. This alternative has the disadvantage of not providing an alternative for users who desire the current
behavior as well as silently breaking any code depending on the current behavior.
Another alternative considered was making Optional
to conform to CustomStringConvertible
and let the user choose between
.description
which would provide the same behavior as the proposed .descriptionWithDefaultValue()
, and .debugDescription
which would maintain its current behavior. It has been pointed out, however, that both properties are explicitly discouraged
in the documentation from being invoked directly.
In order to make this as robust as possible and extendable on other types, an empty protocol Uninterpolable
would be
included in the standard library. When a type conforming to Uninterpolable
(which Optional
would be conforming to)
is used for string interpolation, the compiler would emit a warning about the interpolation.
While such a deprecation can be handled by the following code (which would be included in the Swift library),
support from the compiler itself is also needed in order to provide a fix-it suggestion. If the use of
Uninterpolable
within the interpolation is intentional, casting it as Any
can be appended to silence
the warning, which would be the default Fix-It suggestion and in the case of interpolation of Optional
,
the current behavior would be maintained, requiring the user to supply the alternate solution.
/// Protocol to provide warnings when a type is used for string interpolation.
protocol Uninterpolable {}
/// Optional is Uninterpolable.
extension Optional: Uninterpolable {}
extension String {
/// Deprecating interpolation of all Uninterpolable types.
@available(*, deprecated, message="Interpolation of this type is deprecated.")
init(stringInterpolationSegment segment: Uninterpolable) {
self.init(stringInterpolationSegment: segment as Any)
}
}
- All these “Optional(foo)” things showing up in user-facing strings are a pain, and since they don’t show up until runtime, it’s really easy to miss them. --Charles Srstka, cocoadev@charlessoft.com
- Instead of
\(optional)
having to do\(optional ?? "")
or whatever fallback string you want is not that cumbersome and can prevent Optional(Foo) sort of strings from appearing in user facing text, which I have seen in several shipping app store apps already. --Javier Soto, javier.api@gmail.com - Strong +1 for the (at least) warning in case of optional in string interpolation. --Vladimir.S, svabox@gmail.com
- +1, personally I have taken to using
x+"str"+y
instead of"\(x)str\(y)"
, if x/y are strings, so I can get a compile-time error if I do this accidentally. --Jacob Bandes-Storch, jtbandes@gmail.com