[swift-evolution] Proposal: Deprecate optionals in string interpolation

Nicola Salmoria nicola.salmoria at gmail.com
Tue May 24 06:25:27 CDT 2016

On Tue, May 24, 2016 at 12:01 PM, Charlie Monroe <charlie at charliemonroe.net>

> Hi Nicola, thanks for the feedback.
> > I assume you mean "at runtime" here?
> That's probably my wrong wording. :) The unexpected result is at runtime,
> but we'd like to catch this at compile time. I've updated it to say
> "in order to prevent unexpected results already at compile time" -
> hopefully that's a clearer wording.

Aha, now I understand :-)

Perhaps "in order to detect potentially undesired behavior at compile time"
would be even clearer?

> > I think the detailed design needs  some more thought. The
> "Uninterpolable"
> > protocol, and suggesting to cast "as Any" in a Fix-it both seem hacks.
> Originally, the proposal was simply to emit a warning for interpolation of
> Optionals, but several people made good points:
> - there may be other types you may not want to use for interpolation - as
> mentioned in the proposal, e.g. private data structures that would expose
> something you want to keep private, various enum values, etc. Which is why
> I've started thinking about making a protocol that would indicate the type
> is discouraged being "interpoled". I've thought about this and decided to
> make a more robust and customizable solution.

I'm not sure if this is a strong enough motivation.
The customization point already provided by the language is
CustomStringConvertible. That's the place where one can provide a readable
description, hiding implementation details.

> An alternative to this would be to use annotations or just drop this
> customizability completely. But I think with Swift and its protocol-driven
> development, marking the type with this protocol is the most robust way to
> go.
> - both .description and .debugDescription are mentioned in alternatives
> for the Fix-It.

The direct use of .description and .debugDescription is discouraged in the
API docs, so I don't think this is a viable option.

> "as Any" seemed, however, the cleanest and most robust solution to me,
> since then the Uninterpolable protocol can be applied to any type without
> forcing the type to conform to CustomStringConvertible as well. I agree
> that it's kind of a hack, though.
> > I'm not even sure if the general direction of a compile time warning is
> the
> > right one, and if the problem wouldn't be better solved by simply not
> making
> > Optional put "Optional()" around the value in its .description.
> There are many people oposing this and expecting the Optional() wrap
> around the value, indicating the actual type. Actually, including me - I
> agree it can be useful for some types of debugging since in what you wrote
> further, there'd be no difference between description of [1, 2, 3] (i.e.
> [Int]) and Optional([1, 2, 3]) (i.e. [Int]?).

There's also no difference between print(Int(1)) and print(UInt(1)): they
both output just "1".

I think "debugging" is the key word here. If the distinction between
CustomStringConvertible and CustomDebugStringConvertible is supposed to be
between providing a user-friendly description and a description useful for
debugging, I think it makes sense to make the former as terse as possible
and the latter as informative as possible.

> There are legitimate usecases where the current behavior is correct, but
> in most of cases, having an optional in string interpolation will lead
> either to unnecessary clutter in the log/console or bugs - in which case
> even "nil" is not correct to be used for the interpolation. Which is the
> basis for this proposal.
> > print("\(o)")               // "Optional(1)", why??
> String has several overloads for the init(stringInterpolationSegment:)
> initiailizer. Optional falls into the generic <T> category, which will call
> String(optional) - which most likely uses debugDescription.
This is the relevant code:

I presume that it shouldn't be a problem to change it to use
CustomStringConvertible instead.

The above code also hints that there's another odd behavior in the current

struct Foo: CustomStringConvertible, CustomDebugStringConvertible {
    var description: String { return "normal" }
    var debugDescription: String { return "debug" }

let f = Foo()
let of = Optional(f)

print(f)        // "normal": ok
debugPrint(f)   // "debug": ok
print(of)       // "Optional(debug)": unexpected
debugPrint(of)  // "Optional(debug)": ok

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160524/243c1dcf/attachment.html>

More information about the swift-evolution mailing list