<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""><div><blockquote type="cite" class=""><div class="">On Jun 2, 2016, at 1:55 PM, Austin Zheng via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div dir="ltr" class="">I think we should actually go further.<div class=""><br class=""></div><div class="">If this proposal is accepted, disallow "as" as a way of specifying the type to construct from a literal.</div></div></div></blockquote><div><br class=""></div><div>I’m not sure. I agree it would be bad style to use `as` here. But I’m not sure if it should be banned or not.</div><div><br class=""></div><blockquote type="cite" class=""><div class=""><div dir="ltr" class=""><div class=""><br class=""></div><div class="">If this proposal isn't accepted, disallow using literal values as the argument to one-unlabeled-argument constructors.</div></div></div></blockquote><div><br class=""></div><div>I don’t know about this. It says that if you want users to initialize your type with an unlabeled argument that has a type which has a corresponding literal you *must* conform to the corresponding literal convertible protocol. Do we really want to require that? Maybe, but maybe not. We definitely *should not* allow such an initializer to be written if it cannot be called with a literal.</div><div><br class=""></div><div>For example, if I have:</div><div><br class=""></div><div>`init(_ a: [String])`</div><div><br class=""></div><div>users could call the initializer with an array variable but not a array literal. That would be very bad IMO. Either this initializer is banned altogether, or we allow it to be called with a literal. </div><div><br class=""></div><div>FWIW, there are types in the standard library with overlapping initializers in this new model:</div><div><br class=""></div><div>public init(_ value: UInt8)</div><div>public init(integerLiteral value: UInt8)</div><div><br class=""></div><div>I’m not sure whether they actually need to do different things or whether they are just provided so you can initialize the type with a variable and also use literals in a context expecting that type.</div><div><br class=""></div><div>I think it’s important to understand whether overlap like this is necessary or not. If behavior should always be identical I am in favor of refactoring the literal convertible protocols as part of this change.</div><br class=""><blockquote type="cite" class=""><div class=""><div dir="ltr" class=""><div class=""><br class=""></div><div class="">In either case we should disabuse users of the notion that A(literal) is an initializer that behaves exactly the same as other initializers.</div><div class=""><br class=""></div><div class="">Austin</div></div><div class="gmail_extra"><br class=""><div class="gmail_quote">On Thu, Jun 2, 2016 at 11:46 AM, Austin Zheng <span dir="ltr" class=""><<a href="mailto:austinzheng@gmail.com" target="_blank" class="">austinzheng@gmail.com</a>></span> wrote:<br class=""><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr" class="">+1.<div class=""><br class=""></div><div class="">The primary advantage is that it aligns the language semantics with how most programmers expect this common C-language-family idiom to behave and removes a potential source of silently wrong code.</div><div class=""><br class=""></div><div class="">The primary disadvantage is that it introduces special-case behavior to certain types of initializers (although, to be fair, this special-case behavior is easily recognizable: unlabeled one-argument initializer with a literal as the argument).</div><div class=""><br class=""></div><div class="">I think the advantage outweighs the disadvantage.</div><div class=""><br class=""></div><div class="">This problem should be addressed one way or another. I prefer this solution, but if it is rejected for whatever reason we should at least explicitly outlaw A(literal) syntax in favor of "literal as A".</div><span class="HOEnZb"><font color="#888888" class=""><div class=""><br class=""></div><div class="">Austin</div></font></span></div><div class="gmail_extra"><br class=""><div class="gmail_quote"><div class=""><div class="h5">On Thu, Jun 2, 2016 at 9:08 AM, John McCall via swift-evolution <span dir="ltr" class=""><<a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a>></span> wrote:<br class=""></div></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class=""><div class="h5"><div style="word-wrap:break-word" class="">The official way to build a literal of a specific type is to write the literal in an explicitly-typed context, like so:<div class=""><font face="Andale Mono" class=""> let x: UInt16 = 7</font></div><div class="">or</div><div class=""><font face="Andale Mono" class=""> let x = 7 as UInt16</font></div><div class=""><br class=""></div><div class="">Nonetheless, programmers often try the following:</div><div class=""><font face="Andale Mono" class=""> UInt16(7)</font></div><div class=""><br class=""></div><div class="">Unfortunately, this does <i class="">not</i> attempt to construct the value using the appropriate literal protocol; it instead performs overload resolution using the standard rules, i.e. considering only single-argument unlabelled initializers of a type which conforms to IntegerLiteralConvertible. Often this leads to static ambiguities or, worse, causes the literal to be built using a default type (such as Int); this may have semantically very different results which are only caught at runtime.</div><div class=""><br class=""></div><div class="">In my opinion, using this initializer-call syntax to build an explicitly-typed literal is an obvious and natural choice with several advantages over the "as" syntax. However, even if you disagree, it's clear that programmers are going to continue to independently try to use it, so it's really unfortunate for it to be subtly wrong.</div><div class=""><br class=""></div><div class="">Therefore, I propose that we adopt the following typing rule:</div><div class=""><br class=""></div><div class=""> Given a function call expression of the form A(B) (that is, an <i class="">expr-call</i> with a single, unlabelled argument) where B is an <i class="">expr-literal</i> or <i class="">expr-collection</i>, if A has type T.Type for some type T and there is a declared conformance of T to an appropriate literal protocol for B, then the expression is always resolves as a literal construction of type T (as if the expression were written "B as A") rather than as a general initializer call.</div><div class=""><br class=""></div><div class="">Formally, this would be a special form of the argument conversion constraint, since the type of the expression A may not be immediately known.</div><div class=""><br class=""></div><div class="">Note that, as specified, it is possible to suppress this typing rule by wrapping the literal in parentheses. This might seem distasteful; it would be easy enough to allow the form of B to include extra parentheses. It's potentially useful to have a way to suppress this rule and get a normal construction, but there are several other ways of getting that effect, such as explicitly typing the literal argument (e.g. writing "A(Int(B))").</div><div class=""><br class=""></div><div class="">A conditional conformance counts as a declared conformance even if the generic arguments are known to not satisfy the conditional conformance. This permits the applicability of the rule to be decided without having to first decide the type arguments, which greatly simplifies the type-checking problem (and may be necessary for soundness; I didn't explore this in depth, but it certainly feels like a very nasty sort of dependence). We could potentially weaken this for cases where A is a direct type reference with bound parameters, e.g. Foo<Int>([]) or the same with a typealias, but I think there's some benefit from having a simpler specification, both for the implementation and for the explicability of the model.</div><span class=""><font color="#888888" class=""><div class=""><br class=""></div><div class="">John.</div></font></span></div><br class=""></div></div><span class="">_______________________________________________<br class="">
swift-evolution mailing list<br class="">
<a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a><br class="">
<a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br class="">
<br class=""></span></blockquote></div><br class=""></div>
</blockquote></div><br class=""></div>
_______________________________________________<br class="">swift-evolution mailing list<br class=""><a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a><br class="">https://lists.swift.org/mailman/listinfo/swift-evolution<br class=""></div></blockquote></div><br class=""></body></html>