[Returned for revision] SE-0089: Renaming String.init<T>(_: T)

Does "lossless" preclude floating-point numbers from being printed in
decimal unless they are exactly representable?

···

On Fri, May 27, 2016 at 9:04 PM Austin Zheng via swift-evolution < swift-evolution@swift.org> wrote:

Thanks, I like "Lossless" too. Further suggestions on naming would be
appreciated from anyone.

Austin

On May 27, 2016, at 9:03 PM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

This looks good. I like your use of the term "lossless"; perhaps we can
use it consistently, i.e. LosslessStringConvertible. The implication by
comparison would be that CustomStringConvertible makes no guarantee of
losslessness.
On Fri, May 27, 2016 at 23:52 Austin Zheng via swift-evolution < > swift-evolution@swift.org> wrote:

Hello swift-evolution,

I've put together a preliminary v2 of the proposal, taking into account
feedback expressed on this thread. I would appreciate any comments,
suggestions, or criticisms.

https://github.com/austinzheng/swift-evolution/blob/az-edit-89/proposals/0089-rename-string-reflection-init.md

If any objections can be worked out quickly, I hope to resubmit this
proposal for review early next week.

Best,
Austin

On Fri, May 27, 2016 at 7:50 PM, Patrick Smith via swift-evolution < >> swift-evolution@swift.org> wrote:

Is there any possibility we can break from this? Especially as:

1. ValuePreservingStringConvertible expects its description to be value
preserving, but current Cocoa implementations are not.
2. ‘Description’ doesn’t really convey the meaning of ‘value preserving’
in my mind, but is a valuable name for many other use cases.
3. Swift 3 has a wide range of breaking changes for the better.
4. With the presence of ValuePreservingStringConvertible,
CustomStringConvertible doesn’t seem to provide much value over
CustomDebugStringConvertible?

For string interpolation, I imagine the standard library could fall back
to a ‘description’ method for NSObject subclasses.

Thanks,

Patrick

> On 28 May 2016, at 7:49 AM, Dave Abrahams via swift-evolution < >>> swift-evolution@swift.org> wrote:
>
>
> on Thu May 26 2016, Patrick Smith <swift-evolution@swift.org> wrote:
>
>>> On 27 May 2016, at 2:40 PM, Austin Zheng via swift-evolution < >>> swift-evolution@swift.org> wrote:
>>>
>>> Any of the NSObject subclass candidates may require their
>>> `description`s to be altered to meet the semantics, which may or may
>>> not be an acceptable breaking change.
>>
>> Do you think it might be worth changing `description` to be named
>> something else? Something more clear, less likely to conflict with
>> ‘real’ properties — ‘description’ doesn’t seem to portray something
>> that is value-preserving. What is the reason for calling it
>> ‘description’?
>
> The main reason was backward compatibility with Cocoa, which already
has
> a “description” property.
>
>> Especially if NSObject subclasses won’t fit, then why not have a
>> different method that can be strictly value preserving? (Then
>> `description` can stay being an NSObject thing.)
>
> --
> Dave
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

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

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

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

I'd hope not. You can't guarantee String -> Double -> String roundtripping,
but Double -> String -> Double should be lossless.

···

On Sat, May 28, 2016 at 00:11 Jacob Bandes-Storch <jtbandes@gmail.com> wrote:

Does "lossless" preclude floating-point numbers from being printed in
decimal unless they are exactly representable?

On Fri, May 27, 2016 at 9:04 PM Austin Zheng via swift-evolution < > swift-evolution@swift.org> wrote:

Thanks, I like "Lossless" too. Further suggestions on naming would be
appreciated from anyone.

Austin

On May 27, 2016, at 9:03 PM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

This looks good. I like your use of the term "lossless"; perhaps we can
use it consistently, i.e. LosslessStringConvertible. The implication by
comparison would be that CustomStringConvertible makes no guarantee of
losslessness.
On Fri, May 27, 2016 at 23:52 Austin Zheng via swift-evolution < >> swift-evolution@swift.org> wrote:

Hello swift-evolution,

I've put together a preliminary v2 of the proposal, taking into account
feedback expressed on this thread. I would appreciate any comments,
suggestions, or criticisms.

https://github.com/austinzheng/swift-evolution/blob/az-edit-89/proposals/0089-rename-string-reflection-init.md

If any objections can be worked out quickly, I hope to resubmit this
proposal for review early next week.

Best,
Austin

On Fri, May 27, 2016 at 7:50 PM, Patrick Smith via swift-evolution < >>> swift-evolution@swift.org> wrote:

Is there any possibility we can break from this? Especially as:

1. ValuePreservingStringConvertible expects its description to be value
preserving, but current Cocoa implementations are not.
2. ‘Description’ doesn’t really convey the meaning of ‘value
preserving’ in my mind, but is a valuable name for many other use cases.
3. Swift 3 has a wide range of breaking changes for the better.
4. With the presence of ValuePreservingStringConvertible,
CustomStringConvertible doesn’t seem to provide much value over
CustomDebugStringConvertible?

For string interpolation, I imagine the standard library could fall
back to a ‘description’ method for NSObject subclasses.

Thanks,

Patrick

> On 28 May 2016, at 7:49 AM, Dave Abrahams via swift-evolution < >>>> swift-evolution@swift.org> wrote:
>
>
> on Thu May 26 2016, Patrick Smith <swift-evolution@swift.org> wrote:
>
>>> On 27 May 2016, at 2:40 PM, Austin Zheng via swift-evolution < >>>> swift-evolution@swift.org> wrote:
>>>
>>> Any of the NSObject subclass candidates may require their
>>> `description`s to be altered to meet the semantics, which may or may
>>> not be an acceptable breaking change.
>>
>> Do you think it might be worth changing `description` to be named
>> something else? Something more clear, less likely to conflict with
>> ‘real’ properties — ‘description’ doesn’t seem to portray something
>> that is value-preserving. What is the reason for calling it
>> ‘description’?
>
> The main reason was backward compatibility with Cocoa, which already
has
> a “description” property.
>
>> Especially if NSObject subclasses won’t fit, then why not have a
>> different method that can be strictly value preserving? (Then
>> `description` can stay being an NSObject thing.)
>
> --
> Dave
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

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

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

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

I don't recall whether it was in this thread or another that this point was
made by the core team, but if I'm remembering correctly: it was shared that
the protocol is now called CustomStringConvertible because conforming types
provide a *custom* description, not merely an ordinary description.

If we follow that reasoning, ValuePreservingStringConvertible should *not*
conform to CustomStringConvertible, because whether the description is
value-preserving is orthogonal to whether it has been customized.

But I share your concern that attempting to delete description from Swift
will only increase interoperability headaches rather than freeing the name
for other uses.

···

On Sat, May 28, 2016 at 00:36 Brent Royal-Gordon via swift-evolution < swift-evolution@swift.org> wrote:

>
https://github.com/austinzheng/swift-evolution/blob/az-edit-89/proposals/0089-rename-string-reflection-init.md

I prefer the more conservative and backwards-compatible option of using
`description` and conforming `ValuePreservingStringConvertible` to
`CustomStringConvertible`.

This is for three reasons:

* ValuePreservingStringConvertible really is a refinement of
CustomStringConvertible's semantic; a value-preserving `description` should
always be acceptable as an ordinary `description`.

* You should not call `description` directly anyway; you should call
`String.init(_:)`. That makes the arguably non-descriptive name a lot less
important.

* Changing the name of this property now will not actually make
`description` available for the uses you want to put it to in most code. No
amount of monkeying with the Swift standard library in 2016 can change the
fact that the OpenStep specification took that name in 1994, and we need to
interoperate with that heritage. You might free up the name `description`
in value types and Linux-only code, but only at the cost of
interoperability headaches. I don't think that's worth it.

I also think that, if we're serious about
ValuePreservingStringConvertible's initializer restoring the full state of
the instance, then it is a full-width conversion and doesn't need a label.

So, here's what I suggest:

        protocol CustomStringConvertible {
                var description: String { get }
        }
        protocol ValuePreservingStringConvertible: CustomStringConvertible
{
                init?(_ description: String)
        }
        extension String {
                init<Value: ValuePreservingStringConvertible>(_ value:
Value) { ... }
                init<Value>(describing value: Value) { ... }
        }

Actually, I'd *like* to see `String.init(describing:)` constrained to
CustomStringConvertible, but I've lost that argument before.

("Lossless" instead of "ValuePreserving" is fine too, perhaps even
slightly better.)

--
Brent Royal-Gordon
Architechies

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

-1 I like the original design for the fact that it does not give "description", which nobody would have proposed Swift had started as a blank slate, center stage: promoting it to protocol membership would perpetuate something that people should no longer be focussing on. So although I do prefer definition over convention, this is an exception I do not mind making.

-1 for Lossless. ValuePreserving is clear as to WHAT it does, LossLess describes HOW it operates, relegating the value preservation to being a side effect that people have to infer themselves: "if this thing operates in a loss less manner, then I must be getting back what I put in".

···

On May 28, 2016, at 6:36 AM, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> wrote:

https://github.com/austinzheng/swift-evolution/blob/az-edit-89/proposals/0089-rename-string-reflection-init.md

I prefer the more conservative and backwards-compatible option of using `description` and conforming `ValuePreservingStringConvertible` to `CustomStringConvertible`.

This is for three reasons:

* ValuePreservingStringConvertible really is a refinement of CustomStringConvertible's semantic; a value-preserving `description` should always be acceptable as an ordinary `description`.

* You should not call `description` directly anyway; you should call `String.init(_:)`. That makes the arguably non-descriptive name a lot less important.

* Changing the name of this property now will not actually make `description` available for the uses you want to put it to in most code. No amount of monkeying with the Swift standard library in 2016 can change the fact that the OpenStep specification took that name in 1994, and we need to interoperate with that heritage. You might free up the name `description` in value types and Linux-only code, but only at the cost of interoperability headaches. I don't think that's worth it.

I also think that, if we're serious about ValuePreservingStringConvertible's initializer restoring the full state of the instance, then it is a full-width conversion and doesn't need a label.

So, here's what I suggest:

   protocol CustomStringConvertible {
       var description: String { get }
   }
   protocol ValuePreservingStringConvertible: CustomStringConvertible {
       init?(_ description: String)
   }
   extension String {
       init<Value: ValuePreservingStringConvertible>(_ value: Value) { ... }
       init<Value>(describing value: Value) { ... }
   }

Actually, I'd *like* to see `String.init(describing:)` constrained to CustomStringConvertible, but I've lost that argument before.

("Lossless" instead of "ValuePreserving" is fine too, perhaps even slightly better.)

--
Brent Royal-Gordon
Architechies

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

I don't recall whether it was in this thread or another that this point was made by the core team, but if I'm remembering correctly: it was shared that the protocol is now called CustomStringConvertible because conforming types provide a *custom* description, not merely an ordinary description.

If we follow that reasoning, ValuePreservingStringConvertible should *not* conform to CustomStringConvertible, because whether the description is value-preserving is orthogonal to whether it has been customized.

IMO "Custom" evoques a general set, of which "ValuePreserving" is a subset.

···

On May 28, 2016, at 7:49 AM, Xiaodi Wu via swift-evolution <swift-evolution@swift.org> wrote:

But I share your concern that attempting to delete description from Swift will only increase interoperability headaches rather than freeing the name for other uses.

On Sat, May 28, 2016 at 00:36 Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> wrote:
> https://github.com/austinzheng/swift-evolution/blob/az-edit-89/proposals/0089-rename-string-reflection-init.md

I prefer the more conservative and backwards-compatible option of using `description` and conforming `ValuePreservingStringConvertible` to `CustomStringConvertible`.

This is for three reasons:

* ValuePreservingStringConvertible really is a refinement of CustomStringConvertible's semantic; a value-preserving `description` should always be acceptable as an ordinary `description`.

* You should not call `description` directly anyway; you should call `String.init(_:)`. That makes the arguably non-descriptive name a lot less important.

* Changing the name of this property now will not actually make `description` available for the uses you want to put it to in most code. No amount of monkeying with the Swift standard library in 2016 can change the fact that the OpenStep specification took that name in 1994, and we need to interoperate with that heritage. You might free up the name `description` in value types and Linux-only code, but only at the cost of interoperability headaches. I don't think that's worth it.

I also think that, if we're serious about ValuePreservingStringConvertible's initializer restoring the full state of the instance, then it is a full-width conversion and doesn't need a label.

So, here's what I suggest:

        protocol CustomStringConvertible {
                var description: String { get }
        }
        protocol ValuePreservingStringConvertible: CustomStringConvertible {
                init?(_ description: String)
        }
        extension String {
                init<Value: ValuePreservingStringConvertible>(_ value: Value) { ... }
                init<Value>(describing value: Value) { ... }
        }

Actually, I'd *like* to see `String.init(describing:)` constrained to CustomStringConvertible, but I've lost that argument before.

("Lossless" instead of "ValuePreserving" is fine too, perhaps even slightly better.)

--
Brent Royal-Gordon
Architechies

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

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

Personally, independent of the Cocoa precedent, I think that keeping “description” as the requirement of ValuePreservingStringConvertible is the right thing to do.

Here is the proposed schema (ignoring the related but different “debug description”):

1) Values can always be converted to a string in Swift through reflection.
2) If a value wants a better, or more customized, string form, then it conforms to CustomStringConvertible.
3) If that string form is value preserving, it conforms to ValuePreservingStringConvertible, which is a refinement of CustomStringConvertible.

In other words, this approach is saying that a value may be convertible to string in exactly one way. If that way is value preserving (i.e., can be reversed as DaveA suggests) then it can do so by conforming to the more specific protocol. The advantage of doing this is that it is now eligible for the String(x) syntax.

This seems clean and simple. The only advantage to adding a new “stringRepresentation” requirement is if you wanted “description” to return one thing, but “stringRepresentation” to return another thing. There may be use cases for such a thing, but to me it just seems like new complexity added to the model for very little gain.

-Chris

···

On May 27, 2016, at 7:50 PM, Patrick Smith via swift-evolution <swift-evolution@swift.org> wrote:

Is there any possibility we can break from this? Especially as:

1. ValuePreservingStringConvertible expects its description to be value preserving, but current Cocoa implementations are not.
2. ‘Description’ doesn’t really convey the meaning of ‘value preserving’ in my mind, but is a valuable name for many other use cases.
3. Swift 3 has a wide range of breaking changes for the better.
4. With the presence of ValuePreservingStringConvertible, CustomStringConvertible doesn’t seem to provide much value over CustomDebugStringConvertible?

For string interpolation, I imagine the standard library could fall back to a ‘description’ method for NSObject subclasses.

No, FP types should be able to conform. There are algorithms that are guaranteed to turn IEEE floating point values into a decimal representation in a reversible way.

I don’t think we care about NaN payloads, but an encoding could be created for them as well.

-Chris

···

On May 27, 2016, at 9:10 PM, Jacob Bandes-Storch via swift-evolution <swift-evolution@swift.org> wrote:

Does "lossless" preclude floating-point numbers from being printed in decimal unless they are exactly representable?

https://github.com/austinzheng/swift-evolution/blob/az-edit-89/proposals/0089-rename-string-reflection-init.md

I prefer the more conservative and backwards-compatible option of using `description` and conforming `ValuePreservingStringConvertible` to `CustomStringConvertible`.

This is for three reasons:

+1 to all of your points.

("Lossless" instead of "ValuePreserving" is fine too, perhaps even slightly better.)

I agree, even though Lossless seems less specific, it does seem like it would feel more comfortable sitting next to “Custom”.

-Chris

···

On May 27, 2016, at 9:36 PM, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> wrote:

Thank you for doing this Austin!

Here are some random comments:

"which accidentally invokes this initializer by accident” -> "which accidentally invokes this initializer”

"A new protocol will be introduced: ValuePreservingStringConvertible. “ -> Thanks for adding the init requirement. It might be worth mentioning up at top that an alternative name to consider is “LosslessStringConvertible”.

"protocol ValuePreservingStringConvertible {“ -> "protocol ValuePreservingStringConvertible : CustomStringConvertible {"

" var stringRepresentation : String { get }"

Just speaking for my opinion, but I think this is better to keep as description. We don’t want multiple different string forms, because at the end of the day string literal interpolation and print need to do “something”, and description should be that default form. If that form isn’t lossless, then the type shouldn’t have access to the labelless string initializer.

  init?(stringRepresentation: String)

Since this is a lossless conversion when it succeeds, it should be unlabeled.

"The standard library will be audited."

This is prescriptive statement: the proposal should include the actual list of types in the stdlib.

"The Foundation SDK overlay will be audited in the same manner.”

-> Foundation is handled separately, it should be left out of the proposal.

"If they conform to CustomStringConvertible and their existing description is value-preserving, stringRepresentation will simply return description."

With the structure above, this isn’t necessary.

Thank you for driving this forward Austin!

-Chris

···

On May 27, 2016, at 8:51 PM, Austin Zheng via swift-evolution <swift-evolution@swift.org> wrote:

Hello swift-evolution,

I've put together a preliminary v2 of the proposal, taking into account feedback expressed on this thread. I would appreciate any comments, suggestions, or criticisms.

https://github.com/austinzheng/swift-evolution/blob/az-edit-89/proposals/0089-rename-string-reflection-init.md

If any objections can be worked out quickly, I hope to resubmit this proposal for review early next week.

Some feedback:

I wonder if ValuePreservingStringConvertible having an initializer restricts its use case at all? Plus, ValuePreservingStringConvertible seems very similar to RawRepresentable with a RawValue of String.

Lossless sounds nice to me. Or ‘canonical’ I had wondered, but lossless sounds better.

• The standard library will be audited. Any type which can be reasonably represented as a string in a value-preserving way will be modified to conform to ValuePreservingStringConvertible. If they conform to CustomStringConvertible and their existing description is value-preserving, stringRepresentation will simply return description.

···

---
I think this should instead say description will simply return stringRepresentation, as it is more of a source of truth, and description is derivative

• CustomStringConvertible will provide a human-readable description of an instance. It may provide as little or as much detail as deemed appropriate.
• CustomDebugStringConvertible will provide a human-readable description of an instance. It can provide additional information relative to CustomStringConvertible, information that would not be pertinent for consumers of descriptions (such as human readers or other APIs), but would be useful for development or diagnostic purposes.
---
I think this reasoning for having both CustomStringConvertible and CustomDebugStringConvertible doesn’t really hold up. It’s a little bit vague. If it’s for an API, then the lossless value is the better choice. If it’s for people, then either a localised value (which description is not) or the lossless string representation is a better choice.

I know I keep repeating this, but I can’t see any use cases for a ‘description’ property. I think ‘stringRepresentation’ and ‘debugDescription’ cover all use cases. The ‘description’ property is never accessed by developers, instead as the Swift team’s feedback said `String.init<T>(describing: T)` or `"\(interpolation)"` is to be used, and I think they can detect and fallback to `NSObject.description’ for Objective-C objects, e.g. in _print_unlocked() here: https://github.com/apple/swift/blob/cf73dd9177c231a15429b08ae889e94f20e53f50/stdlib/public/core/OutputStream.swift#L319

Not having ‘description’ taken means we can create a struct like so without clashing:

struct Channel {
  let title: String
  let link: NSURL
  let description: String
}

Patrick

On 28 May 2016, at 1:51 PM, Austin Zheng <austinzheng@gmail.com> wrote:

Hello swift-evolution,

I've put together a preliminary v2 of the proposal, taking into account feedback expressed on this thread. I would appreciate any comments, suggestions, or criticisms.

https://github.com/austinzheng/swift-evolution/blob/az-edit-89/proposals/0089-rename-string-reflection-init.md

If any objections can be worked out quickly, I hope to resubmit this proposal for review early next week.

Best,
Austin

On Fri, May 27, 2016 at 7:50 PM, Patrick Smith via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
Is there any possibility we can break from this? Especially as:

1. ValuePreservingStringConvertible expects its description to be value preserving, but current Cocoa implementations are not.
2. ‘Description’ doesn’t really convey the meaning of ‘value preserving’ in my mind, but is a valuable name for many other use cases.
3. Swift 3 has a wide range of breaking changes for the better.
4. With the presence of ValuePreservingStringConvertible, CustomStringConvertible doesn’t seem to provide much value over CustomDebugStringConvertible?

For string interpolation, I imagine the standard library could fall back to a ‘description’ method for NSObject subclasses.

Thanks,

Patrick

> On 28 May 2016, at 7:49 AM, Dave Abrahams via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>
>
> on Thu May 26 2016, Patrick Smith <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>
>>> On 27 May 2016, at 2:40 PM, Austin Zheng via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>>>
>>> Any of the NSObject subclass candidates may require their
>>> `description`s to be altered to meet the semantics, which may or may
>>> not be an acceptable breaking change.
>>
>> Do you think it might be worth changing `description` to be named
>> something else? Something more clear, less likely to conflict with
>> ‘real’ properties — ‘description’ doesn’t seem to portray something
>> that is value-preserving. What is the reason for calling it
>> ‘description’?
>
> The main reason was backward compatibility with Cocoa, which already has
> a “description” property.
>
>> Especially if NSObject subclasses won’t fit, then why not have a
>> different method that can be strictly value preserving? (Then
>> `description` can stay being an NSObject thing.)
>
> --
> Dave
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
> https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

If anyone is curious, the revised proposal can be found here: https://github.com/austinzheng/swift-evolution/blob/2b31df6163f5c5d1975a37e72c6996b82d61a5c6/proposals/0089-rename-string-reflection-init.md

This is great. My only suggestion is that `init?(description: String)` should be `init?(_ description: String)`, since by definition the conversion is fullwidth. But you may already be planning to incorporate that change, since Chris mentioned it.

Just quickly scanning the docs on swiftdoc.org, here are protocols which I think should conform to LosslessStringConvertible:

* FloatingPoint
* Integer
* Boolean?

And here are concrete types:

* Bool (if not Boolean)
* Character
* String (kind of circular, but I think it's a good idea) and its views
* String.Index? (Not sure how to represent this; UTF-8 offset, maybe?)
* UnicodeScalar

Protocols which would require conditional conformances:

* RangeReplaceableCollection where Iterator.Element == Character or UnicodeScalar
* SetAlgebra where Iterator.Element == Character or UnicodeScalar

These protocols were chosen because they include `init<S: Sequence where S.Iterator.Element == Iterator.Element>(_: S)` initializers.

Generic types which would require conditional conformances:

* ClosedRange where Bound: LosslessStringConvertible
* CountableClosedRange where Bound: LosslessStringConvertible
* CountableRange where Bound: LosslessStringConvertible
* Range where Bound: LosslessStringConvertible

These would be non-trivial, but useful. They could have a serialization like:

  var description: String {
    let operator = "..<" // or "..." for the closed ranges
    func escape(_ string: String) -> String {
      let escapedOperator = String(operator.characters.flatMap { ["\\", $0] })
      return string.replacingOccurrences(of: "\\", with: "\\\\").replacingOccurrences(of: operator, with: escapedOperator)
    }
    
    return escape(String(lowerBound)) + " " + operator + " " + escape(String(upperBound))
  }

The `init(_: String)` method would need to handle the escapes—hence the nontrivial-ness.

Technically possible, but probably unwise:

* ObjectIdentifier
* UnsafePointer and friends
* Set.Index and Dictionary.Index

···

--
Brent Royal-Gordon
Architechies

Thanks!

The PR I submitted earlier should have an updated version of the proposal which takes most of your feedback into account. I'll amend it later to address the rest.

···

Sent from my iPhone

On May 28, 2016, at 1:33 PM, Chris Lattner <clattner@apple.com> wrote:

On May 27, 2016, at 8:51 PM, Austin Zheng via swift-evolution <swift-evolution@swift.org> wrote:

Hello swift-evolution,

I've put together a preliminary v2 of the proposal, taking into account feedback expressed on this thread. I would appreciate any comments, suggestions, or criticisms.

https://github.com/austinzheng/swift-evolution/blob/az-edit-89/proposals/0089-rename-string-reflection-init.md

If any objections can be worked out quickly, I hope to resubmit this proposal for review early next week.

Thank you for doing this Austin!

Here are some random comments:

"which accidentally invokes this initializer by accident” -> "which accidentally invokes this initializer”

"A new protocol will be introduced: ValuePreservingStringConvertible. “ -> Thanks for adding the init requirement. It might be worth mentioning up at top that an alternative name to consider is “LosslessStringConvertible”.

"protocol ValuePreservingStringConvertible {“ -> "protocol ValuePreservingStringConvertible : CustomStringConvertible {"

" var stringRepresentation : String { get }"

Just speaking for my opinion, but I think this is better to keep as description. We don’t want multiple different string forms, because at the end of the day string literal interpolation and print need to do “something”, and description should be that default form. If that form isn’t lossless, then the type shouldn’t have access to the labelless string initializer.

  init?(stringRepresentation: String)

Since this is a lossless conversion when it succeeds, it should be unlabeled.

"The standard library will be audited."

This is prescriptive statement: the proposal should include the actual list of types in the stdlib.

"The Foundation SDK overlay will be audited in the same manner.”

-> Foundation is handled separately, it should be left out of the proposal.

"If they conform to CustomStringConvertible and their existing description is value-preserving, stringRepresentation will simply return description."

With the structure above, this isn’t necessary.

Thank you for driving this forward Austin!

-Chris

Fantastic, thanks to both of you. I merged it here:

Please let me know if you’d like any other changes, I’ll kick off the review on Tuesday.

-Chris

···

On May 28, 2016, at 3:33 PM, Brent Royal-Gordon <brent@architechies.com> wrote:

If anyone is curious, the revised proposal can be found here: https://github.com/austinzheng/swift-evolution/blob/2b31df6163f5c5d1975a37e72c6996b82d61a5c6/proposals/0089-rename-string-reflection-init.md

This is great. My only suggestion is that `init?(description: String)` should be `init?(_ description: String)`, since by definition the conversion is fullwidth. But you may already be planning to incorporate that change, since Chris mentioned it.

Just quickly scanning the docs on swiftdoc.org, here are protocols which I think should conform to LosslessStringConvertible:

* FloatingPoint
* Integer
* Boolean?

And here are concrete types:

* Bool (if not Boolean)
* Character
* String (kind of circular, but I think it's a good idea) and its views
* String.Index? (Not sure how to represent this; UTF-8 offset, maybe?)
* UnicodeScalar

Protocols which would require conditional conformances:

* RangeReplaceableCollection where Iterator.Element == Character or UnicodeScalar
* SetAlgebra where Iterator.Element == Character or UnicodeScalar

These protocols were chosen because they include `init<S: Sequence where S.Iterator.Element == Iterator.Element>(_: S)` initializers.

Generic types which would require conditional conformances:

* ClosedRange where Bound: LosslessStringConvertible
* CountableClosedRange where Bound: LosslessStringConvertible
* CountableRange where Bound: LosslessStringConvertible
* Range where Bound: LosslessStringConvertible

These would be non-trivial, but useful. They could have a serialization like:

  var description: String {
    let operator = "..<" // or "..." for the closed ranges
    func escape(_ string: String) -> String {
      let escapedOperator = String(operator.characters.flatMap { ["\\", $0] })
      return string.replacingOccurrences(of: "\\", with: "\\\\").replacingOccurrences(of: operator, with: escapedOperator)
    }
    
    return escape(String(lowerBound)) + " " + operator + " " + escape(String(upperBound))
  }

The `init(_: String)` method would need to handle the escapes—hence the nontrivial-ness.

Technically possible, but probably unwise:

* ObjectIdentifier
* UnsafePointer and friends
* Set.Index and Dictionary.Index

--
Brent Royal-Gordon
Architechies

Thanks for replying Chris!

···

On 29 May 2016, at 6:00 AM, Chris Lattner <clattner@apple.com> wrote:

2) If a value wants a better, or more customized, string form, then it conforms to CustomStringConvertible.

What are the use cases for this more customized string form? If it is for the programmer, then debugDescription seems to be a better fit? For Playgrounds, the CustomPlaygroundQuickLookable protocol is used.

What are its other use cases? APIs? What about Streamable? Does this not take the same responsibility — it converts the receiver into a string? Here it seems like it trumps CustomStringConvertible with string conversion: https://github.com/apple/swift/blob/cf73dd9177c231a15429b08ae889e94f20e53f50/stdlib/public/core/OutputStream.swift#L332

Patrick

1) Values can always be converted to a string in Swift through reflection.

> 2) If a value wants a better, or more customized, string form, then it conforms to CustomStringConvertible.
> 3) If that string form is value preserving, it conforms to ValuePreservingStringConvertible, which is a refinement of CustomStringConvertible.

I can't understand this. For me ValuePreservingStringConvertible usually will be different than CustomStringConvertible. Can't I want to have some string view of my struct to present data(also in UI) *and* value preserving string value for the same struct?
So my .description will show something like "12.345-6.78" and value preserving string will contain something like "19083749347923847293487293483" to encode the data of the struct. No?

Btw, also I can't understand how we can use `description` property name to contain 'value preserving' string. IMO 'description' in this case does not reflect the meaning of contained data.

···

On 28.05.2016 23:00, Chris Lattner via swift-evolution wrote:

On May 27, 2016, at 7:50 PM, Patrick Smith via swift-evolution <swift-evolution@swift.org> wrote:

Is there any possibility we can break from this? Especially as:

1. ValuePreservingStringConvertible expects its description to be value preserving, but current Cocoa implementations are not.
2. ‘Description’ doesn’t really convey the meaning of ‘value preserving’ in my mind, but is a valuable name for many other use cases.
3. Swift 3 has a wide range of breaking changes for the better.
4. With the presence of ValuePreservingStringConvertible, CustomStringConvertible doesn’t seem to provide much value over CustomDebugStringConvertible?

For string interpolation, I imagine the standard library could fall back to a ‘description’ method for NSObject subclasses.

Personally, independent of the Cocoa precedent, I think that keeping “description” as the requirement of ValuePreservingStringConvertible is the right thing to do.

Here is the proposed schema (ignoring the related but different “debug description”):

1) Values can always be converted to a string in Swift through reflection.
2) If a value wants a better, or more customized, string form, then it conforms to CustomStringConvertible.
3) If that string form is value preserving, it conforms to ValuePreservingStringConvertible, which is a refinement of CustomStringConvertible.

In other words, this approach is saying that a value may be convertible to string in exactly one way. If that way is value preserving (i.e., can be reversed as DaveA suggests) then it can do so by conforming to the more specific protocol. The advantage of doing this is that it is now eligible for the String(x) syntax.

This seems clean and simple. The only advantage to adding a new “stringRepresentation” requirement is if you wanted “description” to return one thing, but “stringRepresentation” to return another thing. There may be use cases for such a thing, but to me it just seems like new complexity added to the model for very little gain.

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

print() and string interpolation use it. You conform to it and implement it when you want something specific to your type, otherwise you get the default reflection based implementation. The reflection implementation is better than nothing, but usually not what you want.

-Chris

···

On May 28, 2016, at 10:46 PM, Patrick Smith <pgwsmith@gmail.com> wrote:

Thanks for replying Chris!

On 29 May 2016, at 6:00 AM, Chris Lattner <clattner@apple.com> wrote:

2) If a value wants a better, or more customized, string form, then it conforms to CustomStringConvertible.

What are the use cases for this more customized string form?

I can't understand this. For me ValuePreservingStringConvertible usually will be different than CustomStringConvertible. Can't I want to have some string view of my struct to present data(also in UI) *and* value preserving string value for the same struct?
So my .description will show something like "12.345-6.78" and value preserving string will contain something like "19083749347923847293487293483" to encode the data of the struct. No?

Rather than thinking of LosslessStringConvertible as a protocol for serializing data into a string, think of it as a protocol for those cases where the human-readable description is also parseable and can be used to completely recreate the instance. It's something you would use for things like command-line arguments, environment variables, interactive command-line programs, and configuration files that you expect humans to read and write by hand.

  func prompt<T: LosslessStringConvertible>(for field: String, of type: T.Type) -> T {
    while true {
      print("What's your \(field)?")
      
      let line = readline()
      
      if !line.isEmpty
        let value = T(line) { // how the hell do you indent this stupid syntax?
        return value
      }
    }
  }
  
  let name = prompt(for: "name", of: String)
  let age = prompt(for: "age", of: Int)
    
  let answer = age < 13 ? " not" : ""
  print("\(name), you are\(answer) too old to have a favorite color.")

In other words, write the `description` first, and then decide if you can write a good `init(_ description:)` to match it.

···

--
Brent Royal-Gordon
Architechies

Thanks Chris. I just meant where is that string going?

To a developer -> CustomDebugStringConvertible / Reflection
To standard output -> Streamable
To a user -> NSLocalizedString — no protocol (yet?)
To an API / for serialisation -> LosslessStringConvertible
To a playground -> CustomPlaygroundQuickLookable

CustomStringConvertible is left over, but doesn’t have a use case? Unless it’s an alternative to Streamable, but then why have Streamable? People will use ‘description’ for multiple use cases, which makes sense when you are both a developer and a user, or your users are developers like with a command-line tool, so there doesn’t seem to be any grey. But I believe there is, and that it is beneficial to pin it to one of the use cases above, and to have dedicated clear-cut protocols for each use case.

I’m not sure if anyone else shares the concern, so I’ll leave it. I do believe it’s important however.

Patrick

···

On 30 May 2016, at 5:16 AM, Chris Lattner <clattner@apple.com> wrote:

On May 28, 2016, at 10:46 PM, Patrick Smith <pgwsmith@gmail.com> wrote:

Thanks for replying Chris!

On 29 May 2016, at 6:00 AM, Chris Lattner <clattner@apple.com> wrote:

2) If a value wants a better, or more customized, string form, then it conforms to CustomStringConvertible.

What are the use cases for this more customized string form?

print() and string interpolation use it. You conform to it and implement it when you want something specific to your type, otherwise you get the default reflection based implementation. The reflection implementation is better than nothing, but usually not what you want.

-Chris

Thank you, Brent. But for me you just described a serialization to/from string ;)

So, using your example, if I have

struct A: CustomStringConvertible {
     var a = 0, b = 0
     var description: String { return "a:\(a) b:\(b)" }
}

and I want to use it in your code. Will I be able to do this?
For example, I'm ok to give it 'lossless' representation as "\(a)/\(b)" (i.e. 1/2 for example) and provide init() for string of such format.

I.e. it seems like I just should create extension and conform to LosslessStringConvertible, but as I understand I can't, as I need not only introduce an init(:String), but modify `description` property ?
I.e. assume you have no rights or don't want to modify the A type itself.

This is why I don't understand why we should have the same .description for this LosslessStringConvertible(i.e. if it will be .loslessDescription - no problems).
Most likely I don't understand something.

Also there is a question regarding your example: what to do with Double type? We can have some configuration items of Double type, but how to use this LosslessStringConvertible here?

···

On 31.05.2016 0:22, Brent Royal-Gordon wrote:

I can't understand this. For me ValuePreservingStringConvertible usually will be different than CustomStringConvertible. Can't I want to have some string view of my struct to present data(also in UI) *and* value preserving string value for the same struct?
So my .description will show something like "12.345-6.78" and value preserving string will contain something like "19083749347923847293487293483" to encode the data of the struct. No?

Rather than thinking of LosslessStringConvertible as a protocol for serializing data into a string, think of it as a protocol for those cases where the human-readable description is also parseable and can be used to completely recreate the instance. It's something you would use for things like command-line arguments, environment variables, interactive command-line programs, and configuration files that you expect humans to read and write by hand.

  func prompt<T: LosslessStringConvertible>(for field: String, of type: T.Type) -> T {
    while true {
      print("What's your \(field)?")
      
      let line = readline()
      
      if !line.isEmpty
        let value = T(line) { // how the hell do you indent this stupid syntax?
        return value
      }
    }
  }
  
  let name = prompt(for: "name", of: String)
  let age = prompt(for: "age", of: Int)
    
  let answer = age < 13 ? " not" : ""
  print("\(name), you are\(answer) too old to have a favorite color.")

In other words, write the `description` first, and then decide if you can write a good `init(_ description:)` to match it.

Thanks Chris. I just meant where is that string going?

To a developer -> CustomDebugStringConvertible / Reflection
To standard output -> Streamable
To a user -> NSLocalizedString — no protocol (yet?)
To an API / for serialisation -> LosslessStringConvertible
To a playground -> CustomPlaygroundQuickLookable

CustomStringConvertible is left over, but doesn’t have a use case? Unless it’s an alternative to Streamable, but then why have Streamable?

There are *very* few conformances to Streamable in the standard library—just Character, String, and UnicodeScalar. I think that Streamable is for data that can be *directly* written to an output stream, whereas CustomStringConvertible is a way to convert an instance that *isn't* directly Streamable into something Streamable.

So, here's my version of your table:

User-readable, nonlocalized: CustomStringConvertible
User- and machine-readable, nonlocalized: LosslessStringConvertible
User-readable, localized: (nothing)
Developer-readable: CustomDebugStringConvertible

(Playground isn't necessarily working with strings, so it doesn't belong in this list.)

Localization is an obvious hole in our string conversions, but I think the reality here is that localization is part of a higher layer than the standard library. From what I can see, all of the "standard library" APIs which handle localization are actually part of Foundation. I'm sure that, if we build any localization-related features into the language, we'll add basic supporting code to the standard library if needed, but other than that, I don't think the standard library is the right place.

I’m not sure if anyone else shares the concern, so I’ll leave it. I do believe it’s important however.

I do think this is an important concern, and I also think it's important to ask how interpolation interacts with it. For instance, I think it would be very useful to be able to say "interpolate developer representations" or "interpolate user representations" or "interpolate localized user representations", and have the compiler reject interpolated expressions which don't have the necessary representation.

···

--
Brent Royal-Gordon
Architechies