Default String conversion of Optional

(Another thread has reminded me this topic.)

In the current Swift standard library, two text representations for Optional are the same.

var str: String? = "Hello, playground"
String(str) //->Optional("Hello, playground")
String(reflecting: str) //->Optional("Hello, playground")


Why cannot the default string conversion be simpler like this:

extension Optional: CustomStringConvertible {
    public var description: String {
        if self == nil {
            return ""
        } else {
            return String(self!)
        }
    }
}


String(str) //->Hello, playground
"concatenated:\(str)" //->concatenated:Hello, playground

Replies

I don't understand why that would be a good thing. It would make some issues hard to track down by collapsing the differences between Strings and Optional Strings, and .Some("") and .None.

I know in some use cases distinguishing Strings and Optional Strings is important, also in some other cases we do not need the string containing "Optional".

And if you want such distinguishable text representation, you can use .debugDescription or String.init(reflecting:) .


One very bad thing is that we cannot get any messages when converting Optionals to String, neither with String.init nor string interpolation.

Which is often not we intend.

Alternatively, if you want an indistinguishable text representation you can use ?? "". It seems a lot more helpful to people still learning about Optionals to make the distinction clear, than to just print nothing when they're trying to print what they think is an Integer, etc. In other words, if you try to print something and the description is wrapped in “Optional(…)” then that provides a lot of hints as to what is going on and where to track down the problem. If it sometimes prints the description and sometimes prints nothing then the symptom is much harder to match to a cause.

What you're asking is "How come String(...) doesn't implicitly unwrap optional values?" and you don't seem to see the fundamental inconsistency that doing so would cause.


Or, to put it in bullet points:

  • If you don't like the behavior, you've already demonstrated the simple extension you can use instead.
  • Consinstency. If you want the value unwrapped, you should specify the appropriate ! or ? to do so.
  • The Optional(...) format allows for reasonable debugging statements. Was the value nil, the empty string, or a string with just a space in it? With Optional(" ") you can tell.

Thanks for replying. I really expect many other developers express their optinions.

What you're asking is "How come String(...) doesn't implicitly unwrap optional values?"

No. I'm discussing about the default text representation of optionals.


If you don't like the behavior, you've already demonstrated the simple extension you can use instead.

As I said, I'm discussing about how default behavior should be. Do you think, when we can write an extension, you should not talk about how defaults should be?


Consinstency. If you want the value unwrapped, you should specify the appropriate ! or ? to do so.

What do you think you need to generate a text representation yourself, you need to concatenate as "Optional(\"" + (String representation of unwrapped value) + "\")". It's just a problem of choice. An empty string for nil is a choice, and "nil" for nil is another.


The Optional(...) format allows for reasonable debugging statements. Was the value nil, the empty string, or a string with just a space in it? With Optional(" ") you can tell.

I already said it's useful for some cases, especially for debugging statements. So, for that purpose, we have debugDescription and Sting(reflecting:).

Alternatively, if you want an indistinguishable text representation you can use ?? "".

Yes, in fact I use so many `?? ""`s. As you know, you can use `?? ""` inside string interpolations since Swift 2.1, how nice!

And seeing the places where I put `?? ""`, most of them are suggested by Swift at compile-time. (Or I should say edit-time.)


It seems a lot more helpful to people still learning about Optionals to make the distinction clear

I really want to hear which should be better for starting learners, which hides some mistakenly used Optionals or embedding a character sequence of "Optional". In my opinion, we should recommend using debugDescription, which may easily help us finding invisible characters contained in the string.


Why I used "very bad" in the former post, is because we first know that we mistakenly put Optionals inside String.init or string interpolations at runtime.

As noted, Swift warns us many things about Optionals, like "should be unwrapped" at compile-time, but once enclosed in String.init or string interpolations, Swift silently accept it and generates unexpected result.


So, another choice is showing warnings when Optionals are put inside String.init or string interpolation, to avoid such warnings, we can use debugDescription or String(reflecting:) .