# How to avoid calling CustomStringConvertible.description as a property?

**URL:** <https://forums.swift.org/t/how-to-avoid-calling-customstringconvertible-description-as-a-property/72605>\
**Category:** Using Swift\
**Created:** [June 19, 2024, 7:09pm UTC](https://forums.swift.org/t/how-to-avoid-calling-customstringconvertible-description-as-a-property/72605 "2024-06-19T19:09:54Z")\
**Posts on this page:** 15\
**Page:** 1

<div class="post-metadata">

**Author:** ![taylorswift](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/taylorswift/32/43413_2.png) [@taylorswift](https://forums.swift.org/u/taylorswift)\
**Post date:** [June 19, 2024, 7:09pm UTC](https://forums.swift.org/t/how-to-avoid-calling-customstringconvertible-description-as-a-property/72605/1 "2024-06-19T19:09:54Z")

</div>

[`CustomStringConvertible`](https://swiftinit.org/docs/swift/swift/customstringconvertible.description) is pretty adamant that `description` should not be called directly.

> Calling this property directly is discouraged. Instead, convert an instance of any type to a string by using the `String(describing:)` initializer. This initializer works with any type, and uses the custom `description` property for types that conform to `CustomStringConvertible`:

accordingly, i try to write string conversions with interpolations (`"\(x)"`) whenever possible. but this gets pretty awkward when you try to combine it with optional chaining, because you wind up with contortions like

```swift
return (article?.title).map { "\($0)" } 
    ?? (fallback?.title).map { "\($0)" }
    ?? "some fallback for the fallback"

```

alternatively:

```swift
return (article?.title).map(String.init(describing:))
    ?? (fallback?.title).map(String.init(describing:))    
    ?? "some fallback for the fallback"

```

what is the right way to express these kinds of string conversions? i have a hard time understanding how this is preferable to a simple

```swift
return article?.title.description
    ?? fallback?.title.description
    ?? "some fallback for the fallback"

```

---

<div class="post-metadata">

**Author:** ![itaiferber](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/itaiferber/32/33840_2.png) [@itaiferber](https://forums.swift.org/u/itaiferber)\
**Post date:** [June 19, 2024, 7:27pm UTC](https://forums.swift.org/t/how-to-avoid-calling-customstringconvertible-description-as-a-property/72605/2 "2024-06-19T19:27:08Z")

</div>

Out of curiosity, what's the type of `title` on these values, and what's the context for grabbing `description` instead of a more semantic property? (e.g., are you implementing `description` for a type which contains `article`/`fallback`?)

---

<div class="post-metadata">

**Author:** ![taylorswift](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/taylorswift/32/43413_2.png) [@taylorswift](https://forums.swift.org/u/taylorswift)\
**Post date:** [June 19, 2024, 7:29pm UTC](https://forums.swift.org/t/how-to-avoid-calling-customstringconvertible-description-as-a-property/72605/3 "2024-06-19T19:29:23Z")

</div>

in this example, `title` was some `Markdown.Bytecode` that is normally rendered to HTML. however, it can also be rendered to plain text, which is what i was doing here, and the interface for that is `CustomStringConvertible`, via `description`.

---

<div class="post-metadata">

**Author:** ![itaiferber](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/itaiferber/32/33840_2.png) [@itaiferber](https://forums.swift.org/u/itaiferber)\
**Post date:** [June 19, 2024, 7:32pm UTC](https://forums.swift.org/t/how-to-avoid-calling-customstringconvertible-description-as-a-property/72605/4 "2024-06-19T19:32:29Z")

</div>

I wonder if you wouldn't be better served offering

```swift
var plainText: String {
    ...
}

var description: String {
    plainText
}

```

if you care about the semantics and want to be guaranteed to be working with some stable value.

**Edit:** Jinx

---

<div class="post-metadata">

**Author:** ![xwu](https://avatars.discourse-cdn.com/v4/letter/x/b487fb/32.png) [@xwu](https://forums.swift.org/u/xwu)\
**Post date:** [June 19, 2024, 7:32pm UTC](https://forums.swift.org/t/how-to-avoid-calling-customstringconvertible-description-as-a-property/72605/5 "2024-06-19T19:32:49Z")

</div>

> [@taylorswift](#):
>
> in this example, `title` was some `Markdown.Bytecode` that is normally rendered to HTML. however, it can also be rendered to plain text, which is what i was doing here, and the interface for that is `CustomStringConvertible`, via `description`.

Sounds like your type guarantees something above and beyond `CustomStringConvertible` for this property; it just happens to fulfill the protocol requirement too.

So my advice would be to feel free to call `description` from the concrete context, or otherwise create a differently named property such as `plainText` if you feel like distinguishing the guarantees of this API from that of `CustomStringConvertible.description`.

[Edit: Samesies with what @itaiferber said. Geez, we even chose the same name for the property.]

---

<div class="post-metadata">

**Author:** ![Andropov](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/andropov/32/35955_2.png) [@Andropov](https://forums.swift.org/u/Andropov)\
**Post date:** [June 19, 2024, 7:39pm UTC](https://forums.swift.org/t/how-to-avoid-calling-customstringconvertible-description-as-a-property/72605/6 "2024-06-19T19:39:40Z")

</div>

Hmm. It's interesting that `CustomStringConvertible` doesn't mention _why_ `String(describing:)` is the preferred method of converting a value of `Any` type to a `String`.

It looks like at some point the documentation for `CustomStringConvertible` [used to say](https://github.com/apple/swift/blob/7f31d4e8890e227a8c291d28d7646784dd26ebc6/stdlib/public/core/OutputStream.swift#L44):

> This textual representation is used when values are written to an _output stream_, for example, by `print`.

But it no longer says so. Is it possible that the original goal of `CustomStringConvertible` was to be a tool to customize the output of functions like `print` and **not** as a general way to expose a `var description: String`, even though a lot of people ended up using it as such? That would explain the seemingly bizarre discouragement of accessing it directly (or using it as a generic constraint).

* * *

FWIW, what I usually do in my own code is to create protocols similar to `CustomStringConvertible` that convey more clearly the intent of that description. For example:

```swift
/// A type with a text representation shown in the UI.
protocol DisplayableString {
    var displayString: String { get }
}

```

---

<div class="post-metadata">

**Author:** ![xwu](https://avatars.discourse-cdn.com/v4/letter/x/b487fb/32.png) [@xwu](https://forums.swift.org/u/xwu)\
**Post date:** [June 19, 2024, 7:44pm UTC](https://forums.swift.org/t/how-to-avoid-calling-customstringconvertible-description-as-a-property/72605/7 "2024-06-19T19:44:56Z")

</div>

To expand on the documentation you're quoting—what it's trying to say is that something like the following is discouraged:

```swift
func f<T: CustomStringConvertible>(_ t: T) {
  print(t.description)
}

```

...because you can instead write:

```swift
func f(_ t: T) {
  print(String(describing: t))
}

```

_Every_ type is string convertible, and there are no semantic guarantees available _solely_ because a type is _custom_ string convertible. Thus, to constrain generic code only to work with types that conform to the protocol is needlessly narrow and never semantically necessary. In other words, by "calling...directly" it's more trying to get at "calling...in generic code."

Any concrete type is free to make load-bearing guarantees of its own `description` property that go beyond this protocol, and calling `description` in concrete code based on those guarantees ought to be no different from calling the concrete implementation of any other property.

---

<div class="post-metadata">

**Author:** ![taylorswift](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/taylorswift/32/43413_2.png) [@taylorswift](https://forums.swift.org/u/taylorswift)\
**Post date:** [June 19, 2024, 7:52pm UTC](https://forums.swift.org/t/how-to-avoid-calling-customstringconvertible-description-as-a-property/72605/8 "2024-06-19T19:52:54Z")

</div>

> [@itaiferber](#):
>
> I wonder if you wouldn't be better served offering
> 
> ```swift
> var plainText: String {
> ...
> }
> 
> var description: String {
> plainText
> }
> 
> ```
> 
> if you care about the semantics and want to be guaranteed to be working with some stable value.

i try to avoid having multiple spellings for the same underlying operation, so when i wrote `Markdown.Bytecode`, i thought that it would be better to avoid having a “forwarding” property like `description`, and just put the implementation in `description` proper, since the type was going to have to conform to `CustomStringConvertible` anyways.

> [@xwu](#):
>
> Sounds like your type guarantees something above and beyond `CustomStringConvertible` for this property; it just happens to fulfill the protocol requirement too.

i’m not sure i understand how the guarantee is different, i’ve always treated `CustomStringConvertible` as meaning “this thing can be converted to a `String`, and `description` is how you do it”. for `Markdown.Bytecode`, rendering to plain text is the only sensible direct `String` conversion; if you want to convert to HTML, you convert through the `HTML` type.

so in my mind, adding a `plainText` property that just returns `description` is like adding a `length` property to `Array` that just returns `count`.

> [@Andropov](#):
>
> FWIW, what I usually do in my own code is to create protocols similar to `CustomStringConvertible` that convey more clearly the intent of that description. For example:

it was originally planned to open-source `Markdown.Bytecode` as a library type, so i did not want users of the library to also have to adopt a particular string conversion framework, which could duplicate or conflict with a `DisplayableString` system the user has already defined for themselves.

> [@xwu](#):
>
> _Every_ type is string convertible, and there are no semantic guarantees available _solely_ because a type is _custom_ string convertible.

the thing is, i don’t really agree with this - every type is string _reflectable_, but not every type is (or should be) string convertible. i can recall exactly zero scenarios outside of debugging/introspection when i intended to convert something to a string by obtaining its reflection. this has almost always been a bug, like `"https://forums.swift.org/\(postID)"` producing `"https://forums.swift.org/PostID(rawValue: 72605)"`.

---

<div class="post-metadata">

**Author:** ![xwu](https://avatars.discourse-cdn.com/v4/letter/x/b487fb/32.png) [@xwu](https://forums.swift.org/u/xwu)\
**Post date:** [June 19, 2024, 8:02pm UTC](https://forums.swift.org/t/how-to-avoid-calling-customstringconvertible-description-as-a-property/72605/9 "2024-06-19T20:02:59Z")

</div>

> [@taylorswift](#):
>
> for `Markdown.Bytecode`, rendering to plain text is the only sensible direct `String` conversion

It would be a perfectly conformant implementation, as far as `CustomStringConvertible` goes, to have `description` for your `Bytecode` type be something like `"(256 bytes)"`.

> [@taylorswift](#):
>
> i don’t really agree with this - every type is string _reflectable_, but not every type is (or should be) string convertible.

`String(reflecting:)` and its property counterpart, `debugDescription`, guarantee a string that's "suitable for debugging"—`description` does not! Rather, it's what you get when you `print` the value, and that in itself is plenty used _even if_ there are exactly zero scenarios besides.

* * *

[Edit: Naturally, you might ask: "Why isn't the protocol just called `Printable` then?" And the answer is...it literally was, up until some release of Swift 2.]

---

<div class="post-metadata">

**Author:** ![itaiferber](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/itaiferber/32/33840_2.png) [@itaiferber](https://forums.swift.org/u/itaiferber)\
**Post date:** [June 19, 2024, 8:05pm UTC](https://forums.swift.org/t/how-to-avoid-calling-customstringconvertible-description-as-a-property/72605/10 "2024-06-19T20:05:25Z")

</div>

> [@taylorswift](#):
>
> i’m not sure i understand how the guarantee is different, i’ve always treated `CustomStringConvertible` as meaning “this thing can be converted to a `String`, and `description` is how you do it”. for `Markdown.Bytecode`, rendering to plain text is the only sensible direct `String` conversion; if you want to convert to HTML, you convert through the `HTML` type.

From the docs:

> Types that conform to the `CustomStringConvertible` protocol can provide their own representation to be used when converting an instance to a string.

`description` will return you _a_ textual representation of your type, but no guarantees are provided about what that representation means. `Markdown.Bytecode` _could_ very well have a description in the format

```swift
<Markdown.Bytecode length=34 depth=2 bytes=...>

```

and this would fit the semantics of `CustomStringConvertible` just fine.

Its discouraged to rely on the result of `description` because it offers no further guarantees beyond "this returns a string".

* * *

What you do with this is up to you. If you want, you could decide for `Markdown.Bytecode` that `description` _is_ the plain text, document it as such, and reference `.description` to your heart's content. Or, you could decide that you'd prefer a representation that's semantically-named and go with `.plainText` (and optionally mirror it in `.description`).

* * *

i.e., what @xwu said

---

<div class="post-metadata">

**Author:** ![taylorswift](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/taylorswift/32/43413_2.png) [@taylorswift](https://forums.swift.org/u/taylorswift)\
**Post date:** [June 19, 2024, 8:17pm UTC](https://forums.swift.org/t/how-to-avoid-calling-customstringconvertible-description-as-a-property/72605/11 "2024-06-19T20:17:59Z")

</div>

> [@xwu](#):
>
> Rather, it's what you get when you `print` the value

well that’s just one interpretation of it. it was probably _the_ interpretation back when it was called `Printable`. but today i find another, more-useful interpretation is that `description` is what you get when you pass it to [`DefaultStringInterpolation.appendInterpolation(_:)`](https://swiftinit.org/docs/swift/swift/defaultstringinterpolation.appendinterpolation(_:)?hash=6KX4D).

> [@itaiferber](#):
>
> `description` will return you _a_ textual representation of your type, but no guarantees are provided about what that representation means. `Markdown.Bytecode` _could_ very well have a description in the format
> 
> ```swift
> <Markdown.Bytecode length=34 depth=2 bytes=...>
> 
> ```

> [@xwu](#):
>
> It would be a perfectly conformant implementation, as far as `CustomStringConvertible` goes, to have `description` for your `Bytecode` type be something like `"(256 bytes)"`.

it _could_, in the sense that it wouldn’t be openly contradicting anything in its docs, but as a practical matter, this is not a good “seating arrangement” so long as `CustomDebugStringConvertible` exists. you would want the object-style representation in logging contexts, and the ‘text’ representation in business logic. if you claim `CustomStringConvertible` for the logging-optimized representation, you don’t have an interoperable way of providing the long-form representation to code in other packages.

---

<div class="post-metadata">

**Author:** ![itaiferber](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/itaiferber/32/33840_2.png) [@itaiferber](https://forums.swift.org/u/itaiferber)\
**Post date:** [June 19, 2024, 8:28pm UTC](https://forums.swift.org/t/how-to-avoid-calling-customstringconvertible-description-as-a-property/72605/12 "2024-06-19T20:28:26Z")

</div>

> [@taylorswift](#):
>
> you would want the object-style representation in logging contexts, and the ‘text’ representation in business logic.

True, but what @xwu and I are claiming is that `CustomStringConvertible` is not a good way to get that "text representation" for business logic. `CustomStringConvertible` is, in practice, how you get types coerced into _some_ string, most often for printing.

It's hard to "reserve" the debug description because even if you offer both `CustomStringConvertible` and `CustomDebugStringConvertible`, it's the former that gets used for string interpolation everywhere. Even for debug logging, you have to be careful to remember to write `"\(x.debugDescription)"` and not `"\(x)"`, which is a pain — and in _practice_, `CustomStringConvertible` is implemented with logging in mind _significantly_ more often than `CustomDebugStringConvertible`.

But again, you can decide on the semantics of your types; if you _define_ `description` to mean the plain text of the type, then you're free to do so, and free to use `.description` directly with no risk.

(And, if you offer your type as public API, consider how API _consumers_ would expect to use the type. I wouldn't find it intuitive at all to get the plain text of a Markdown document via `.description` rather than by a semantically-named property — and in fact, would probably fumble with the API a bit because I'd never consider `.description` to return anything meaningful to me, so I'd never even try it.)

---

<div class="post-metadata">

**Author:** ![taylorswift](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/taylorswift/32/43413_2.png) [@taylorswift](https://forums.swift.org/u/taylorswift)\
**Post date:** [June 19, 2024, 8:45pm UTC](https://forums.swift.org/t/how-to-avoid-calling-customstringconvertible-description-as-a-property/72605/13 "2024-06-19T20:45:09Z")

</div>

at the risk of diving too deep into the weeds, `Markdown.Bytecode` is rarely a document, it is really just a precompiled variation of `AttributedString`. so you would usually use its plain text rendering capabilities like:

```swift
var meta:String 
{
    """
    \(self.displayName) · \
    \(self.followers) Followers · \
    \(self.bio)
    """
}

```

the point of `Markdown.Bytecode` is to avoid having to carry around colorful and plain representations of the same attributed strings, so it’s an explicit goal to make them interpolation-friendly.

it sounds like best thing to do here is probably vend the `plainText` member anyways and prefer `"\(self.bio)"` over `"\(self.bio.plainText)"` as a style guide rule.

---

<div class="post-metadata">

**Author:** ![itaiferber](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/itaiferber/32/33840_2.png) [@itaiferber](https://forums.swift.org/u/itaiferber)\
**Post date:** [June 19, 2024, 9:45pm UTC](https://forums.swift.org/t/how-to-avoid-calling-customstringconvertible-description-as-a-property/72605/14 "2024-06-19T21:45:33Z")

</div>

> [@taylorswift](#):
>
> it is really just a precompiled variation of `AttributedString`

Given this, I think I would be even _more_ surprised as an API consumer that `description` would return a plain text rendering of the string. I would expect printing the string to produce the raw bytes of the text, or some other description; I probably wouldn't even consider checking the documentation of `description` to notice that it would be plain text.

Instead, I would expect to write something like

```swift
var meta: String {
    [
        displayName.plainText,
        followers.plainText + " Followers",
        bio.plainText
    ].joined(separator: " · ")
}

```

I don't think I'd be comfortable relying on string interpolation to combine these, given how unreliable `description`s tend to be.

* * *

**Edit:** to be clear, I think this is a nice _additional_ interface, but not one I would expect or know to reach for. I would still suggest offering both `plainText` _and_ `CustomStringConvertible`

---

<div class="post-metadata">

**Author:** ![Andropov](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/andropov/32/35955_2.png) [@Andropov](https://forums.swift.org/u/Andropov)\
**Post date:** [June 19, 2024, 10:00pm UTC](https://forums.swift.org/t/how-to-avoid-calling-customstringconvertible-description-as-a-property/72605/15 "2024-06-19T22:00:30Z")

</div>

Adding to the discussion of whether API consumers should expect _anything_ from `CustomStringConvertible`'s `description` other than a `String` with some sort of text representation that may be helpful for debugging, there's a [very interesting post on NSHipster about the history of APNS tokens](https://nshipster.com/apns-device-tokens/#nsdata-in-its-own-words) and how, prior to iOS 7, some apps were relying _precisely_ on `description` to get a representation of the memory contents of the backing `NSData` of the APNs device token... until `description` changed (as the underlying type changed from `NSData` into `Data`).

This is obviously not the same thing, but I still think there's a lesson to be learned there that may apply to this. For example, it makes me think about how changes in this (documented, but not obvious in code) expectation of what `description` does would be communicated to users.

If one uses the documentation to direct API consumers towards using `description` for something specific (like the plain text version of `Markdown.Bytecode` in this case), the API maintainers would be heavily tied to that decision forever: to change what `description` means in the future, or deprecate it altogether (if you no longer wanted to offer whatever you told users that `description` should contain) there would be no good way of communicating this to users (unlike with a specific `plainText` property, that you could deprecate to show warnings/errors in code).
