SE-0213 — Literal initialization via coercion

The review of "SE-0213 — Literal initialization via coercion" begins now and runs through May 15th, 2018.

The proposal is available here:

https://github.com/apple/swift-evolution/blob/master/proposals/0213-literal-init-via-coercion.md

Reviews are an important part of the Swift evolution process. All review feedback should be either on this forum thread or, if you'd like, directly in email to me as the review manager. Please put "SE-0213" in the subject line if you email me.

What goes into a review of a proposal?

The goal of the review process is to improve the proposal under review through constructive criticism and, eventually, determine the direction of Swift.

When reviewing a proposal, here are some questions to consider:

  • What is your evaluation of the proposal?

  • Is the problem being addressed significant enough to warrant a change to Swift?

  • Does this proposal fit well with the feel and direction of Swift?

  • If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?

  • How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

As ever, your contributions to the review process are greatly appreciated.

John McCall
Review Manager

12 Likes

What is your evaluation of the proposal?

Huge +1. This makes Type(literal) syntax behave as it obviously should.

Is the problem being addressed significant enough to warrant a change to Swift?

Absolutely. The distinction between Type(literal) and literal as Type has always been subtle and actively harmful in that the former syntax results in surprising bugs that the latter would prevent. I've been bitten by it a few times, and our style guide devotes a section specifically to the differences between Type(literal) and literal as Type. I'll be thrilled to delete those sections once this change is released.

Does this proposal fit well with the feel and direction of Swift?

Yes, it increases safety and correctness of what most users are going to try to do when they want to cast a literal value.

If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?

This aligns with the casting syntax of C++ and Java, so this proposal takes something that behaved subtly different from the same construct in those languages and turns it into something that those users would expect.

How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

Read the proposal, participated in earlier discussions.

15 Likes

Rather than repeating everything, I'll just echo Tony's review. It's great to see this is getting fixed.

2 Likes

@John_McCall just a small question regarding the meta data of this forum, shouldn't we discourage adding links as tags? (I would have removed it, but I'm asking first because it was done by a site admin.)

Sorry, that was not intentional. Fixed.

1 Like

Correction:

This change also makes some of the errors which correctly only happen at runtime become compile-time instead e.g. Character("ab").

should probably read as

This change also makes some of the errors which currently only happen at runtime become compile-time instead e.g. Character("ab").

Fixed! Thank you, @tim1724!

I'm sorry if the answer to this question is obvious. From the proposal:

This behavior could be avoided by spelling initializer call verbosely e.g. UInt32.init(42)

Does this mean it will or that it could, in theory, if decided later?

(And if it will, will it be the only case in which Foo(bar) might not be the same as Foo.init(bar)?)

1 Like

As tony said

+1

Newcomers to Swift are likely to try Type(literal) long before they learn literal as Type. Making these function identically is a Good Idea. I can't think of any particularly good reason not to make this change, unless there are common use cases that it would break. (This seems very unlikely.)

It means 'it will' in this case, and since the proposal addresses only literal arguments it would be the only way to trigger different initializer behavior.

1 Like

This is reaching the end of its review period. Any more comments? In particular, does anyone have reservations about it?

It seems fairly straightforward and “do what I mean” to me, so I didn't feel the need to comment. Re-reading the previous thread about this, it seems like the most opinionated responses were from @xwu, who had an alternative proposal, and @taylorswift and others had some concerns about parentheses (i.e. is Int(1) the same as Int((1)), etc). Neither of these points seem to have been directly addressed in the proposal under review, so they might want comment here if their concerns still hold. If I understand correctly, Discourse will notify them because I mentioned them.

1 Like

I think we can fix the type-checker performance problems and remove all of the hacks we have which is going to be a proper fix for the problem @xwu mentioned.

2 Likes

+1 from me.

It seems like a good move. It's focused enough that it seems uncontroversial.

1 Like

+1. That the behavior is opt-in, by conforming to the relevant ExpressibleBy… protocols, covered my initial worry on reading the summary.

I do share Jens' concern about making T(…) vs T.init(…) be different in behavior, rather than only in notation. Is there actually a place where the caller would need an opt-out from this coercion behavior that couldn't be expressed by explicitly ascribing a type to the argument? Or could T.init(literal) be made to behave the same as T(literal), which would preserve that as only a notational difference?

1 Like

+1 for me overall, but also +1 with:

The core team discussed this today. A line has to be drawn somewhere between this special syntactic rule and a general higher-order use of initializers as functions; let f = T.init is not going to preserve the special rule. In that light, it makes sense to the core team to tie the special behavior to the existing special syntactic rule of type construction: currently, a "call" of T directly is recognized as always meaning a call to an initializer, whereas this syntax simply adjusts that to sometimes construct a literal. T.init is then reserved to always mean a higher-order use of the overloaded initializer set.

The proposal is accepted.

9 Likes