Skip to content

Instantly share code, notes, and snippets.

@charlieMonroe
Last active June 17, 2016 05:40
Show Gist options
  • Save charlieMonroe/82e1519dd2b57029f69bc7abe99d7385 to your computer and use it in GitHub Desktop.
Save charlieMonroe/82e1519dd2b57029f69bc7abe99d7385 to your computer and use it in GitHub Desktop.

Deprecating string interpolation of Optional

  • Proposal: TBD
  • Author: Charlie Monroe
  • Status: TBD
  • Review manager: TBD

Introduction

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

Motivation

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.

Detailed Design

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 either defaultValue or a String created by calling String(self!) (depending on the result of proposal SE-0089).
  • var detailedDescription: String which would return the same value as debugDescription does now, i.e. either nil or Optional(value). Alternative names considered include optionalDescription.
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
	}
	
}

Impact on Existing Code

Optionals used in string interpolations will have to be revised by the user and an automatic Fix-It appending .descriptionWithDefaultValue() can be offered.

Alternatives Considered

Silent Change

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.

Alternate Fix-It

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.

Uninterpolable protocol

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)
	}
	
}

Community Responses

  • 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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment