[swift-dev] Optional to String conversion

Andrew Trick atrick at apple.com
Sat Dec 5 02:33:51 CST 2015


> On Dec 4, 2015, at 10:26 PM, Dmitri Gribenko <gribozavr at gmail.com> wrote:
> 
> On Fri, Dec 4, 2015 at 10:21 PM, Andrew Trick <atrick at apple.com <mailto:atrick at apple.com>> wrote:
>> 
>>> On Dec 4, 2015, at 10:05 PM, Dmitri Gribenko <gribozavr at gmail.com> wrote:
>>> 
>>> On Fri, Dec 4, 2015 at 10:00 PM, Andrew Trick <atrick at apple.com> wrote:
>>>> I’m adding runtime functionality to support optional casts and ran into some Optional to String conversion behavior that is currently somewhat accidental—it will break when I add functionality. I want to understand the desired behavior before doing extra work to fix it.
>>>> 
>>>> Currently swift does this:
>>>> 
>>>>> print(Int?(3))
>>>> Optional(3)
>>>>> print(String?("meow"))
>>>> Optional("meow")
>>>> 
>>>> I think swift should do this:
>>>> 
>>>>> print(Int?(3))
>>>> 3
>>>>> print(String?("meow"))
>>>> "meow"
>>>>> debugPrint(Int?(3))
>>>> Optional(3)
>>>>> debugPrint(String?("meow"))
>>>> Optional("meow")
>>>> 
>>>> When a value already knows how to represent itself as a string, I don't think that the string "Optional" belongs in the textual representation.
>>>> 
>>>> When debugging data structures, it makes sense to include the "Optional" indicator.
>>>> 
>>>> What was the intention here and what do people think is the desired behavior?
>>> 
>>> This behavior was not accidental.  Here's the rationale:
>>> 
>>> If an Optional is nil, it should somehow indicate that.  Whatever the
>>> representation is, it would be engineer-oriented and not suitable for
>>> end users.  Thus, Optional should never be printed to users, it would
>>> only ever be presented to engineers, and thus its print() and
>>> debugPrint() representations should be the same.
>>> 
>>> Dmitri
>> 
>> I think you're saying that it's the programmer's responsibility not to construct a user-visible String from an Optional.
> 
> No, the responsibility is not to display it to users.  It is OK to e.g., log it.
> 
>> By accidental, I mean that Optional does not conform to CustomStringConvertible. If we want "Optional" to be part of the string conversion, then this conformance needs to exist, or I need to add some special handling of Optional. Do you see any problem with me adding that conformance?
> 
> Yes, the same behavior should also apply to any user-defined type: if
> there is only CustomDebugStringConvertible conformance, it should be
> used for String(x) initialization.
> 
>> Incidentally, when *do* we want debug string conversion to deviate? Or is it just a customization point we anticipate to be useful?
> 
> For example, in String: the user-presentable representation is the
> string itself, the engineer-oriented representation shows all special
> characters as escape sequences.
> 
> Dmitri

I understand, thanks for the explanation. But Optionals are not like
other user-defined types in this respect. Let me clarify with an
example...

class A : CustomStringConvertible, CustomDebugStringConvertible { 
    init() {}
    var description: String { get { return "Apple" } } 
    var debugDescription: String { get { return "Swift" } } 
}

print(A?(A()) is CustomStringConvertible)
// true

// Now, Optional does not conform to CustomStringConvertible, but as
// you can see above it is convertible to CustomStringConvertible.
// As print_unlocked is currently written, the behavior should be:
print(String(A?(A())))
Apple

// But as you explained, that is not the behavior we want. We could fix
// it by making Optional counter-intuitively conform to
// CustomStringConvertible. This prevents down conversion to the wrapped
// type, instead printing "Optional" and the payload's debug string.

extension Optional : CustomStringConvertible {
  /// A textual representation of `self`, suitable for debugging.
  ///
  /// Optional has no representation suitable for an output
  /// stream. Consequently, String conversion should always produce a
  /// debug string indicating the Optional type and including the
  /// debug representation of the wrapped type.
  ///
  /// Optional must conform to CustomStringConvertible to avoid
  /// automatic conversion to its wrapped type during String
  /// conversion.
  public var description: String {
    return debugDescription
  }
}
print(String(A?(A())))
Optional(Swift)

I think this is the way to go.

Andy
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-dev/attachments/20151205/029ee5e5/attachment-0001.html>


More information about the swift-dev mailing list