Clarification on the role of `CustomStringConvertible`


(Daniel Dunbar) #1

I would like some clarification regarding the expected role of `CustomStringConvertible` for types which have a natural, lossless, string representation.

I don't have good terminology to use here, but is the expectation that the "textual string representation" is a readable description of the object? This seems to correspond to the synthesized (?) default definition for struct types, as well as some of the uses for Foundation types without natural string representations (i.e. `Foundation.Notification` reports something like "name = foo, object = ..., userInfo = ...").

Or, is the expectation that it provide a string *representation* of the object, for objects where that makes sense. This corresponds to the use in `Foundation.UUID`, or the example of `Point.description` from the stdlib's `CustomStringConvertible` documentation.

Another way of phrasing this question is: for types which have a reversible string representation, should I expect `CustomStringConvertible.description` to give me a string I could use to reconstruct an instance _without_ knowing its type?

And another way (my actual question) is, given a `struct Path` object which contains a path string, what should `print(Path("a"))` print?

- Daniel


(Erica Sadun) #2

I would like some clarification regarding the expected role of `CustomStringConvertible` for types which have a natural, lossless, string representation.

And this is why we started down the road towards clarifying that it wasn't
convertible but a lossy representation. What you really want is a protocol that
represents an isomorphic relationship. RawRepresentable is about as close as
you can get right now.

And "representation" in RawRepresentable actually means "isomorphic conversion
between types". (ish.)

-- E, paging Matthew Johnson to the SE-0041 courtesy phone

p.s. https://github.com/apple/swift-evolution/blob/master/proposals/0041-conversion-protocol-conventions.md

···

On Jun 29, 2016, at 2:33 PM, Daniel Dunbar via swift-users <swift-users@swift.org> wrote:

I don't have good terminology to use here, but is the expectation that the "textual string representation" is a readable description of the object? This seems to correspond to the synthesized (?) default definition for struct types, as well as some of the uses for Foundation types without natural string representations (i.e. `Foundation.Notification` reports something like "name = foo, object = ..., userInfo = ...").

Or, is the expectation that it provide a string *representation* of the object, for objects where that makes sense. This corresponds to the use in `Foundation.UUID`, or the example of `Point.description` from the stdlib's `CustomStringConvertible` documentation.

Another way of phrasing this question is: for types which have a reversible string representation, should I expect `CustomStringConvertible.description` to give me a string I could use to reconstruct an instance _without_ knowing its type?

And another way (my actual question) is, given a `struct Path` object which contains a path string, what should `print(Path("a"))` print?

- Daniel

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


(Brent Royal-Gordon) #3

I would like some clarification regarding the expected role of `CustomStringConvertible` for types which have a natural, lossless, string representation.

I don't have good terminology to use here, but is the expectation that the "textual string representation" is a readable description of the object? This seems to correspond to the synthesized (?) default definition for struct types, as well as some of the uses for Foundation types without natural string representations (i.e. `Foundation.Notification` reports something like "name = foo, object = ..., userInfo = ...").

Or, is the expectation that it provide a string *representation* of the object, for objects where that makes sense. This corresponds to the use in `Foundation.UUID`, or the example of `Point.description` from the stdlib's `CustomStringConvertible` documentation.

CustomStringConvertible is intended to be a non-localized but human-readable representation of the instance. It is permitted to be imprecise or lossy.

Swift takes the position that it should always be possible to convert an instance into some kind of string. For pure Swift types, no default implementation is provided, but String's from-anything initializer itself attempts a number of increasingly desperate fallbacks, like the debugDescription and reflection. Objective-C is a little different; there, NSObject has a `description` property which subclasses can override, and a separate `debugDescription` property which calls through to `description` by default.

What I would suggest is:

* If there's an end-user-readable representation that captures the gist of the instance, use CustomStringConvertible.

* If you want to customize the way it's displayed but the audience is programers, use CustomDebugStringConvertible.

* Always use `String(_:)` (which is going to become `String(describing:)`) or string interpolation, rather than calling .description or .debugDescription directly. That will automatically choose the most human-readable representation available. (If you prefer the debug description, use `String(reflecting:)`.)

Another way of phrasing this question is: for types which have a reversible string representation, should I expect `CustomStringConvertible.description` to give me a string I could use to reconstruct an instance _without_ knowing its type?

In some cases, like Ints or (potentially) UUIDs, the CustomStringConvertible representation actually is lossless and unambiguous and can be converted back into an identical instance. SE-0089 introduces a LosslessStringConvertible protocol which refines CustomStringConvertible to add an `init?(_ description: String)` initializer. There's no guarantee it'll make Swift 3, but people are working on implementing it.

https://github.com/apple/swift-evolution/blob/master/proposals/0089-rename-string-reflection-init.md

However, LosslessStringConvertible should only be used when the *human-readable* representation happens to be machine-readable as well. Human readability is the first priority with `description`.

···

On Jun 29, 2016, at 1:33 PM, Daniel Dunbar via swift-users <swift-users@swift.org> wrote:

--
Brent Royal-Gordon
Architechies


(Matthew Johnson) #4

I would like some clarification regarding the expected role of `CustomStringConvertible` for types which have a natural, lossless, string representation.

And this is why we started down the road towards clarifying that it wasn't
convertible but a lossy representation. What you really want is a protocol that
represents an isomorphic relationship. RawRepresentable is about as close as
you can get right now.

And "representation" in RawRepresentable actually means "isomorphic conversion
between types". (ish.)

-- E, paging Matthew Johnson to the SE-0041 courtesy phone

RawRepresentable does not require isomorphism and in fact conforming types *cannot* express isomorphm through conformances to this protocol due to the failable initializer. RawRepresentable expresses an injective conversion making the inverse a partial function which is why the initializer is failable (https://en.wikipedia.org/wiki/Injective_function). RawRepresentable conformance with a String `RawValue` is exactly the right way to express a lossless String representation in Swift.

Isomorphic relationships require a precise one-to-one correspondence between values of two types (sets in mathematics). They are usually bijective (I didn’t know they aren’t always bijective until I consulted wikipedia!). https://en.wikipedia.org/wiki/Isomorphism https://en.wikipedia.org/wiki/Bijection

A good example of an isomorphism in Swift is CGFloat and Double on platforms where CGFloat is a Double. For any value of one you can convert to the other and convert back to the original type without losing any information in either direction.

···

On Jun 29, 2016, at 3:51 PM, Erica Sadun <erica@ericasadun.com> wrote:
On Jun 29, 2016, at 2:33 PM, Daniel Dunbar via swift-users <swift-users@swift.org> wrote:

p.s. https://github.com/apple/swift-evolution/blob/master/proposals/0041-conversion-protocol-conventions.md

I don't have good terminology to use here, but is the expectation that the "textual string representation" is a readable description of the object? This seems to correspond to the synthesized (?) default definition for struct types, as well as some of the uses for Foundation types without natural string representations (i.e. `Foundation.Notification` reports something like "name = foo, object = ..., userInfo = ...").

Or, is the expectation that it provide a string *representation* of the object, for objects where that makes sense. This corresponds to the use in `Foundation.UUID`, or the example of `Point.description` from the stdlib's `CustomStringConvertible` documentation.

Another way of phrasing this question is: for types which have a reversible string representation, should I expect `CustomStringConvertible.description` to give me a string I could use to reconstruct an instance _without_ knowing its type?

And another way (my actual question) is, given a `struct Path` object which contains a path string, what should `print(Path("a"))` print?

- Daniel

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


(Daniel Dunbar) #5

Thanks for the pointers!

I agree with the motivation in the proposal, unfortunately this doesn't really help address the question of how to understand the current protocol though, unless I am mistaken?

- Daniel

···

On Jun 29, 2016, at 2:37 PM, Matthew Johnson <matthew@anandabits.com> wrote:

On Jun 29, 2016, at 3:51 PM, Erica Sadun <erica@ericasadun.com> wrote:

On Jun 29, 2016, at 2:33 PM, Daniel Dunbar via swift-users <swift-users@swift.org> wrote:

I would like some clarification regarding the expected role of `CustomStringConvertible` for types which have a natural, lossless, string representation.

And this is why we started down the road towards clarifying that it wasn't
convertible but a lossy representation. What you really want is a protocol that
represents an isomorphic relationship. RawRepresentable is about as close as
you can get right now.

And "representation" in RawRepresentable actually means "isomorphic conversion
between types". (ish.)

-- E, paging Matthew Johnson to the SE-0041 courtesy phone

RawRepresentable does not require isomorphism and in fact conforming types *cannot* express isomorphm through conformances to this protocol due to the failable initializer. RawRepresentable expresses an injective conversion making the inverse a partial function which is why the initializer is failable (https://en.wikipedia.org/wiki/Injective_function). RawRepresentable conformance with a String `RawValue` is exactly the right way to express a lossless String representation in Swift.

Isomorphic relationships require a precise one-to-one correspondence between values of two types (sets in mathematics). They are usually bijective (I didn’t know they aren’t always bijective until I consulted wikipedia!). https://en.wikipedia.org/wiki/Isomorphism https://en.wikipedia.org/wiki/Bijection

A good example of an isomorphism in Swift is CGFloat and Double on platforms where CGFloat is a Double. For any value of one you can convert to the other and convert back to the original type without losing any information in either direction.

p.s. https://github.com/apple/swift-evolution/blob/master/proposals/0041-conversion-protocol-conventions.md

I don't have good terminology to use here, but is the expectation that the "textual string representation" is a readable description of the object? This seems to correspond to the synthesized (?) default definition for struct types, as well as some of the uses for Foundation types without natural string representations (i.e. `Foundation.Notification` reports something like "name = foo, object = ..., userInfo = ...").

Or, is the expectation that it provide a string *representation* of the object, for objects where that makes sense. This corresponds to the use in `Foundation.UUID`, or the example of `Point.description` from the stdlib's `CustomStringConvertible` documentation.

Another way of phrasing this question is: for types which have a reversible string representation, should I expect `CustomStringConvertible.description` to give me a string I could use to reconstruct an instance _without_ knowing its type?

And another way (my actual question) is, given a `struct Path` object which contains a path string, what should `print(Path("a"))` print?

- Daniel

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users