[Review] SE-0041: Updating Protocol Naming Conventions for Conversions

UPDATED APPROACH

Our updated approach focuses on the two most important conventions: one for initialization and one for representation.

1. `Initializable`

`Initializable` designates protocols that convert *from* a type or from an associated type mentioned in the protocol name, such as the current `<Type>LiteralConvertible` protocols. This convention would include member requirements for initializers, factory methods, and any other way an instance can be imported to establish a new instance of the conforming type.

For example, conforming to `ArrayLiteralInitializable` would allow a set to be created with `Set(arrayLiteral: <some array>)` and `var set: Set<T> = `.

This phrase replaces the `Creatable` form from our original proposal.

2. `Representable`

`Representable` designates protocols whose primary purpose is to project *to* a type or associated type mentioned in the protocol name. Items in the standard library that would be subsumed into this naming include `CustomStringConvertible`, `CustomDebugStringConvertible`, and `RawRepresentable`, which we imagine would become `CustomStringRepresentable`, `CustomDebugStringRepresentable`, and (as current) `RawRepresentable`.

This second category groups together the `Convertible` and `Representable` categories from our original proposal and is predicated on the feedback from the design team review. The `Representable` designation does not promise bidirectional conversion although some `Representable` protocols may include requirements to allow attempted initialization *from* the type of the representation. Doing so falls outside the naming contract we are proposing.

If we're doing this, I wonder if category 1 shouldn't just be `Convertible`. This would preserve our `LiteralConvertible` protocols with the same names (which, consistency issues aside, seem perfectly cromulent), while shifting the `StringConvertible` protocols over to the `Representable` category.

···

--
Brent Royal-Gordon
Architechies

I like those a lot. Crystal clear.

···

On 11 May 2016, at 05:14, Patrick Smith via swift-evolution <swift-evolution@swift.org> wrote:

How about:

Consuming (from)
Producing (to)

IntegerLiteralConsuming
StringLiteralConsuming

CustomStringProducing
CustomDebugStringProducing

As for something that does both, all I could find was ‘bidirectional’, ‘two-way’, ‘mutual’, ‘duplex’. I tried searching in biology (https://en.wikipedia.org/wiki/Organic_reaction\), but couldn’t find anything. I like the idea of just conforming to both protocols, and some sort of protocol typealias. Or staying with Representable.

On 11 May 2016, at 12:33 PM, Erica Sadun via swift-evolution <swift-evolution@swift.org> wrote:

On May 10, 2016, at 6:51 PM, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

On May 10, 2016, at 11:48 AM, Chris Lattner <clattner@apple.com> wrote:

Hello Swift community,

The review of "SE-0041: Updating Protocol Naming Conventions for Conversions" begins now and runs through May 16. The proposal is available here:

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

Here are comments from someone who preferred to stay anonymous. These are not my own:

* What is your evaluation of the proposal?

I rather agree with the comments mentioned in the proposal from the Standard Library design team, in that I agree with the basic intention of the proposal, but I’m not convinced about the proposed answer. Specifically:

We'd be happy to bikeshed again.

I think fundamentally our take on this is:

* We want there to be a standard that expresses the three conversion/initialization styles.
* We feel the system is currently broken. And we want to have a coherent and settled vision in place for 3, even imperfect.
* We're flexible about the naming but it should be (1) Swifty and (2) well grounded in meaning.

Let me turn the floor over to Matthew here.

-- E

_______________________________________________
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

If anyone wants to look back at the original discussion, you can find it here:

http://thread.gmane.org/gmane.comp.lang.swift.evolution/10883

-- E

···

On May 11, 2016, at 7:29 AM, Matthew Johnson <matthew@anandabits.com> wrote:

We'd be happy to bikeshed again.

I think fundamentally our take on this is:

* We want there to be a standard that expresses the three conversion/initialization styles.
* We feel the system is currently broken. And we want to have a coherent and settled vision in place for 3, even imperfect.
* We're flexible about the naming but it should be (1) Swifty and (2) well grounded in meaning.

Let me turn the floor over to Matthew here.

I agree with Erica here.

There was a significant round of bike shedding that went into this proposal a few months ago, but there is no harm in continuing that exercise now that a broader audience is engaged. As many reviewers have agreed, the important thing is to settle on *something*.

Several reviewers have mentioned Creatable as not feeling Swifty. FWIW, the history behind the name is that we wanted something that will work regardless of the mechanism. It should be a sensible name whether the requirement is an initializer or a factory method.

I'm hoping we can reach a convention that most of us are happy with by the end of the review period.

I appreciate your rework on this - I still don’t understand one thing and disagree with a second:

(1) I don’t understand what the word “Custom” adds to CustomStringRepresentable and CustomDebugStringRepresentable and would drop that prefix (even if it remains Convertible).

We did not introduce "Custom". That is sourced from the Swift core team. Reevaluating that name would have to fall under the umbrella of a separate proposal. Our focus is keyword conventions.

(2) The use case for these two still stands out from every other protocol on the list. The intent is (was) better captured by “Describable”. i.e. these are things for which there is a description. I think it is more descriptive to name them Describable and DebugDescribable.

It is a representation suitable for printing or debug printing. We included them because they are a part of the existing art in the standard library.

-- E

···

On May 14, 2016, at 8:45 AM, Daniel Steinberg via swift-evolution <swift-evolution@swift.org> wrote:

In Swift, every value has a string and a debugging string
representation, synthesized by the runtime. These protocols allow
customizing the default behavior. We don't want users to write any
APIs against these protocols, because it is the wrong thing to do.

In Swift 1, when the protocols were named Printable and
DebugPrintable, many users wrote APIs like this:

func printAll(_ values: [Printable]) {
  for x in values { print(x) }
}

'Printable' is a wrong constraint. Everything is printable, and
user-defined types that are happy with the default string
representation don't customize it; structural types (function types,
tuples) can not adopt a protocol at all. Users can't pass instances
of such types to this overconstrained API. The right API to design
is:

func printAll(_ values: [Any]) {
  for x in values { print(x) }
}

Motivation behind renaming Printable to CustomStringRepresentable was
to discourage writing APIs against these protocols.

Dmitri

···

On Sat, May 14, 2016 at 7:45 AM, Daniel Steinberg via swift-evolution <swift-evolution@swift.org> wrote:

I appreciate your rework on this - I still don’t understand one thing and
disagree with a second:

(1) I don’t understand what the word “Custom” adds to
CustomStringRepresentable and CustomDebugStringRepresentable and would drop
that prefix (even if it remains Convertible).

--
main(i,j){for(i=2;;i++){for(j=2;j<i;j++){if(!(i%j)){j=0;break;}}if
(j){printf("%d\n",i);}}} /*Dmitri Gribenko <gribozavr@gmail.com>*/

UPDATED APPROACH

Our updated approach focuses on the two most important conventions: one for initialization and one for representation.

1. `Initializable`

`Initializable` designates protocols that convert *from* a type or from an associated type mentioned in the protocol name, such as the current `<Type>LiteralConvertible` protocols. This convention would include member requirements for initializers, factory methods, and any other way an instance can be imported to establish a new instance of the conforming type.

For example, conforming to `ArrayLiteralInitializable` would allow a set to be created with `Set(arrayLiteral: <some array>)` and `var set: Set<T> = `.

This phrase replaces the `Creatable` form from our original proposal.

2. `Representable`

`Representable` designates protocols whose primary purpose is to project *to* a type or associated type mentioned in the protocol name. Items in the standard library that would be subsumed into this naming include `CustomStringConvertible`, `CustomDebugStringConvertible`, and `RawRepresentable`, which we imagine would become `CustomStringRepresentable`, `CustomDebugStringRepresentable`, and (as current) `RawRepresentable`.

This second category groups together the `Convertible` and `Representable` categories from our original proposal and is predicated on the feedback from the design team review. The `Representable` designation does not promise bidirectional conversion although some `Representable` protocols may include requirements to allow attempted initialization *from* the type of the representation. Doing so falls outside the naming contract we are proposing.

If we're doing this, I wonder if category 1 shouldn't just be `Convertible`. This would preserve our `LiteralConvertible` protocols with the same names (which, consistency issues aside, seem perfectly cromulent), while shifting the `StringConvertible` protocols over to the `Representable` category.

Do you really think 'Convertible' is more clear than 'Initializable'?

···

Sent from my iPad
On May 17, 2016, at 11:32 PM, Brent Royal-Gordon <brent@architechies.com> wrote:

--
Brent Royal-Gordon
Architechies

If we're doing this, I wonder if category 1 shouldn't just be `Convertible`. This would preserve our `LiteralConvertible` protocols with the same names (which, consistency issues aside, seem perfectly cromulent), while shifting the `StringConvertible` protocols over to the `Representable` category.

Do you really think 'Convertible' is more clear than 'Initializable'?

I don't think `Convertible` is clearer than `Initializable`, but I think it rolls off the tongue better, is easier to spell, is more compatible with non-initializer implementations, and in general wins on a lot of squishy, subjective, hard-to-define axes.

Subjectively, I've noticed that a lot of people *don't* think of things like `Double(myFloat)` as being initializers; they think of them as conversions. To those people, `Convertible` is probably the right name.

···

--
Brent Royal-Gordon
Architechies

If we're doing this, I wonder if category 1 shouldn't just be `Convertible`. This would preserve our `LiteralConvertible` protocols with the same names (which, consistency issues aside, seem perfectly cromulent), while shifting the `StringConvertible` protocols over to the `Representable` category.

Do you really think 'Convertible' is more clear than 'Initializable'?

I don't think `Convertible` is clearer than `Initializable`, but I think it rolls off the tongue better, is easier to spell, is more compatible with non-initializer implementations, and in general wins on a lot of squishy, subjective, hard-to-define axes.

Subjectively, I've noticed that a lot of people *don't* think of things like `Double(myFloat)` as being initializers; they think of them as conversions. To those people, `Convertible` is probably the right name.

Thanks for elaborating. I can see that perspective. It does also have the advantage of being the smallest change from current state.

I certainly wouldn’t oppose this. The most important thing IMO is that we agree on *something*.

···

On May 18, 2016, at 1:52 PM, Brent Royal-Gordon <brent@architechies.com> wrote:

--
Brent Royal-Gordon
Architechies

Isn't it odd that we use four different terms for both kinds of String conversions that we have?

    A1: extension Foo : CustomStringConvertible // proposed: CustomStringRepresentable
    A2: foo.description
    A3: String(foo) // or `String(printing: foo)` if SE-0089 gets accepted
    A4: print(foo)

    B1: extension Foo : CustomDebugStringConvertible // proposed: CustomDebugStringRepresentable
    B2: foo.debugDescription
    B3: String(reflecting: foo)
    B4: debugPrint(foo)

I don't have great suggestions but wouldn't it be better to move the naming of cases 1 & 2 towards the words used in cases 3 & 4?

— Pyry

···

On 18 May 2016, Brent Royal-Gordon wrote:

I don't think `Convertible` is clearer than `Initializable`, but I think it rolls off the tongue better, is easier to spell, is more compatible with non-initializer implementations, and in general wins on a lot of squishy, subjective, hard-to-define axes.

Subjectively, I've noticed that a lot of people *don't* think of things like `Double(myFloat)` as being initializers; they think of them as conversions. To those people, `Convertible` is probably the right name.

If we're doing this, I wonder if category 1 shouldn't just be `Convertible`. This would preserve our `LiteralConvertible` protocols with the same names (which, consistency issues aside, seem perfectly cromulent), while shifting the `StringConvertible` protocols over to the `Representable` category.

Do you really think 'Convertible' is more clear than 'Initializable'?

I don't think `Convertible` is clearer than `Initializable`, but I think it rolls off the tongue better, is easier to spell, is more compatible with non-initializer implementations, and in general wins on a lot of squishy, subjective, hard-to-define axes.

Well put!

-Thorsten

···

Am 18.05.2016 um 20:52 schrieb Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org>:

Subjectively, I've noticed that a lot of people *don't* think of things like `Double(myFloat)` as being initializers; they think of them as conversions. To those people, `Convertible` is probably the right name.

--
Brent Royal-Gordon
Architechies

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

Convertible also tends to implies some semantics, whereas Initializable
just describes a valid syntax. Protocols that merely describe what
you're allowed to write in code but nothing about its meaning are
usually a bad idea.

···

on Wed May 18 2016, Brent Royal-Gordon <swift-evolution@swift.org> wrote:

If we're doing this, I wonder if category 1 shouldn't just be

`Convertible`. This would preserve our `LiteralConvertible`
protocols with the same names (which, consistency issues aside, seem
perfectly cromulent), while shifting the `StringConvertible`
protocols over to the `Representable` category.

Do you really think 'Convertible' is more clear than 'Initializable'?

I don't think `Convertible` is clearer than `Initializable`, but I
think it rolls off the tongue better, is easier to spell, is more
compatible with non-initializer implementations, and in general wins
on a lot of squishy, subjective, hard-to-define axes.

Subjectively, I've noticed that a lot of people *don't* think of
things like `Double(myFloat)` as being initializers; they think of
them as conversions. To those people, `Convertible` is probably the
right name.

--
Dave

The whole discussion started because ArrayLiteralConvertible meant "can be initialized from Array literal", and not "can be converted to array literal", which is what nearly everyone this was presented to in an informal study thought it meant.

-- E

···

On May 18, 2016, at 1:58 PM, Matthew Johnson via swift-evolution <swift-evolution@swift.org> wrote:

On May 18, 2016, at 1:52 PM, Brent Royal-Gordon <brent@architechies.com> wrote:

If we're doing this, I wonder if category 1 shouldn't just be `Convertible`. This would preserve our `LiteralConvertible` protocols with the same names (which, consistency issues aside, seem perfectly cromulent), while shifting the `StringConvertible` protocols over to the `Representable` category.

Do you really think 'Convertible' is more clear than 'Initializable'?

I don't think `Convertible` is clearer than `Initializable`, but I think it rolls off the tongue better, is easier to spell, is more compatible with non-initializer implementations, and in general wins on a lot of squishy, subjective, hard-to-define axes.

Subjectively, I've noticed that a lot of people *don't* think of things like `Double(myFloat)` as being initializers; they think of them as conversions. To those people, `Convertible` is probably the right name.

Thanks for elaborating. I can see that perspective. It does also have the advantage of being the smallest change from current state.

I certainly wouldn’t oppose this. The most important thing IMO is that we agree on *something*.

If we're doing this, I wonder if category 1 shouldn't just be `Convertible`. This would preserve our `LiteralConvertible` protocols with the same names (which, consistency issues aside, seem perfectly cromulent), while shifting the `StringConvertible` protocols over to the `Representable` category.

Do you really think 'Convertible' is more clear than 'Initializable'?

I don't think `Convertible` is clearer than `Initializable`, but I think it rolls off the tongue better, is easier to spell, is more compatible with non-initializer implementations, and in general wins on a lot of squishy, subjective, hard-to-define axes.

Subjectively, I've noticed that a lot of people *don't* think of things like `Double(myFloat)` as being initializers; they think of them as conversions. To those people, `Convertible` is probably the right name.

Thanks for elaborating. I can see that perspective. It does also have the advantage of being the smallest change from current state.

I certainly wouldn’t oppose this. The most important thing IMO is that we agree on *something*.

The whole discussion started because ArrayLiteralConvertible meant "can be initialized from Array literal", and not "can be converted to array literal", which is what nearly everyone this was presented to in an informal study thought it meant.

That was not the genesis of this proposal in my mind. I was frustrated with the different semantics for Convertible between CustomStringConvertible and *LiteralConvertible.

However, I do agree that there is some potential for ambiguity inherent in the term Convertible which is probably how the current conflicting uses arose in the first place.

Whatever we decide to do, I hope we can at least remove the current conflict and have consistent meanings in the standard library!

···

On May 18, 2016, at 3:01 PM, Erica Sadun <erica@ericasadun.com> wrote:

On May 18, 2016, at 1:58 PM, Matthew Johnson via swift-evolution <swift-evolution@swift.org> wrote:

On May 18, 2016, at 1:52 PM, Brent Royal-Gordon <brent@architechies.com> wrote:

-- E

If we're doing this, I wonder if category 1 shouldn't just be

`Convertible`. This would preserve our `LiteralConvertible`
protocols with the same names (which, consistency issues aside,
seem perfectly cromulent), while shifting the `StringConvertible`
protocols over to the `Representable` category.

Do you really think 'Convertible' is more clear than 'Initializable'?

I don't think `Convertible` is clearer than `Initializable`, but I
think it rolls off the tongue better, is easier to spell, is more
compatible with non-initializer implementations, and in general
wins on a lot of squishy, subjective, hard-to-define axes.

Subjectively, I've noticed that a lot of people *don't* think of
things like `Double(myFloat)` as being initializers; they think of
them as conversions. To those people, `Convertible` is probably the
right name.

Thanks for elaborating. I can see that perspective. It does also
have the advantage of being the smallest change from current state.

I certainly wouldn’t oppose this. The most important thing IMO is that we agree on *something*.

The whole discussion started because ArrayLiteralConvertible meant
"can be initialized from Array literal", and not "can be converted to
array literal", which is what nearly everyone this was presented to in
an informal study thought it meant.

Actually, it means “can be the type of an array literal.” An array
literal is an expression, not an object. Roughly speaking, the type
checker decides what type the array literal has by finding the
best-matching type that conform to the protocol, and the code generator
injects the necessary calls to the initializer.

···

on Wed May 18 2016, Erica Sadun <swift-evolution@swift.org> wrote:

On May 18, 2016, at 1:58 PM, Matthew Johnson via swift-evolution <swift-evolution@swift.org> wrote:

On May 18, 2016, at 1:52 PM, Brent Royal-Gordon <brent@architechies.com> wrote:

-- E

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

--
-Dave

The whole discussion started because ArrayLiteralConvertible meant "can be initialized from Array literal", and not "can be converted to array literal", which is what nearly everyone this was presented to in an informal study thought it meant.

That was not the genesis of this proposal in my mind. I was frustrated with the different semantics for Convertible between CustomStringConvertible and *LiteralConvertible.

That's where *I* jumped on board. Sorry, I should have made it clearer.

However, I do agree that there is some potential for ambiguity inherent in the term Convertible which is probably how the current conflicting uses arose in the first place.

Whatever we decide to do, I hope we can at least remove the current conflict and have consistent meanings in the standard library!

No matter how the core team rules, I hope there's an improvement over the status quo.

-- E

The whole discussion started because ArrayLiteralConvertible meant "can be initialized from Array literal", and not "can be converted to array literal", which is what nearly everyone this was presented to in an informal study thought it meant.

That was not the genesis of this proposal in my mind. I was frustrated with the different semantics for Convertible between CustomStringConvertible and *LiteralConvertible.

That's where *I* jumped on board. Sorry, I should have made it clearer.

Sure. :-) I didn’t actually know this until today!

···

On May 18, 2016, at 3:17 PM, Erica Sadun <erica@ericasadun.com> wrote:

However, I do agree that there is some potential for ambiguity inherent in the term Convertible which is probably how the current conflicting uses arose in the first place.

Whatever we decide to do, I hope we can at least remove the current conflict and have consistent meanings in the standard library!

No matter how the core team rules, I hope there's an improvement over the status quo.

-- E

Dave Abrahams wrote:

Erica Sadun wrote:

> The whole discussion started because ArrayLiteralConvertible meant
> "can be initialized from Array literal", and not "can be converted to
> array literal", which is what nearly everyone this was presented to in
> an informal study thought it meant.

Actually, it means “can be the type of an array literal.” An array
literal is an expression, not an object. Roughly speaking, the type
checker decides what type the array literal has by finding the
best-matching type that conform to the protocol, and the code generator
injects the necessary calls to the initializer.

ArrayLiteralExpressible
BooleanLiteralExpressible
CharacterLiteralExpressible (was ExtendedGraphemeClusterLiteralConvertible)
DictionaryLiteralExpressible
FloatingPointLiteralExpressible (was FloatLiteralConvertible)
IntegerLiteralExpressible
NilLiteralExpressible
StringInterpolationExpressible (or InterpolativeStringLiteralExpressible)‡
StringLiteralExpressible
UnicodeScalarLiteralExpressible

‡ <http://thread.gmane.org/gmane.comp.lang.swift.evolution/17229&gt;

-- Ben