Sent from my iPad
> On Jun 2, 2016, at 3:41 PM, John McCall <[email protected]> wrote: > >>> On Jun 2, 2016, at 12:10 PM, Matthew Johnson <[email protected]> wrote: >>> On Jun 2, 2016, at 1:46 PM, Austin Zheng via swift-evolution >>> <[email protected]> wrote: >>> >>> +1. >>> >>> 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. >>> >>> 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). >>> >>> I think the advantage outweighs the disadvantage. >> >> Agree. This change basically means the label isn’t intended to be used by >> callers, but is only present to distinguish the initializer used by the >> protocol from any other unlabeled initializer accepting the same type. But >> conceptually it is treated as the *most specific* unlabelled initializer >> possible, thus winning the overload resolution. >> >> How important is it that we have the ability to distinguish between literals >> and non-literals with the same type? If that isn’t important, maybe the >> literal convertible protocols could be reworked such that the label isn’t >> necessary. That would eliminate the special-case elision of the label. > > There is no way to rework the literal protocols so that this behavior just > falls out. It's easy enough to convince yourself of this if you try to work > through an actual example. Ok, I'll trust you on this point. +1 on the idea as you proposed it. > > John. > >> >>> >>> 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". >>> >>> Austin >>> >>>> On Thu, Jun 2, 2016 at 9:08 AM, John McCall via swift-evolution >>>> <[email protected]> wrote: >>>> The official way to build a literal of a specific type is to write the >>>> literal in an explicitly-typed context, like so: >>>> let x: UInt16 = 7 >>>> or >>>> let x = 7 as UInt16 >>>> >>>> Nonetheless, programmers often try the following: >>>> UInt16(7) >>>> >>>> Unfortunately, this does not 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. >>>> >>>> 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. >>>> >>>> Therefore, I propose that we adopt the following typing rule: >>>> >>>> Given a function call expression of the form A(B) (that is, an expr-call >>>> with a single, unlabelled argument) where B is an expr-literal or >>>> expr-collection, 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. >>>> >>>> Formally, this would be a special form of the argument conversion >>>> constraint, since the type of the expression A may not be immediately >>>> known. >>>> >>>> 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))"). >>>> >>>> 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. >>>> >>>> John. >>>> >>>> _______________________________________________ >>>> swift-evolution mailing list >>>> [email protected] >>>> https://lists.swift.org/mailman/listinfo/swift-evolution >>> >>> _______________________________________________ >>> swift-evolution mailing list >>> [email protected] >>> https://lists.swift.org/mailman/listinfo/swift-evolution >
_______________________________________________ swift-evolution mailing list [email protected] https://lists.swift.org/mailman/listinfo/swift-evolution
