Would it be possible to have a warning on usage if there is an ambiguity here?

Otherwise, if we want T(0) to work, shouldn't we change the initializer 
signatures for LiteralConvertibles to match the desired behavior, rather than 
make it a special case?

-DW

> On Jun 2, 2016, at 1:57 PM, John McCall via swift-evolution 
> <swift-evolution@swift.org> wrote:
> 
>> On Jun 2, 2016, at 10:49 AM, David Sweeris <daveswee...@mac.com 
>> <mailto:daveswee...@mac.com>> wrote:
>> I’m not entirely sure what an “expr-collection” is.
> 
> Collection literals, e.g. [x,y,z] and [a: x, b: y].
> 
>> Does your proposal mean that in this code:
>> func foo() -> Int {...}
>> var w = 0
>> var x = T(foo())
>> var y = T(w)
>> var z = T(0)
>> different initializers would be used for `x`,`y`, and `z`?
> 
> z would be initialized using the literal initializer if T conforms to that 
> protocol, yes.
> 
>> If so, that seems a potential source of much subtler problems.
> 
> Note that this is only an issue for types that conform to the literal 
> protocols.
> 
>> I don’t disagree that you’ve identified a potential source of issues, but 
>> it’s conceivable that there might be circumstances where the "semantically 
>> very different results” are desired. I can’t think of any off the top of my 
>> head, but I’m not convinced that means they don’t exist.
> 
> I do not think that anybody writes UInt64(0) and *wants* the 0 to be built as 
> an Int and then coerced to UInt64.
> 
> John.
> 
>> 
>> So… I’m tentatively -1
>> 
>> - Dave Sweeris
>> 
>>> On Jun 2, 2016, at 11:08 AM, John McCall via swift-evolution 
>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> 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
>>> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
>>> https://lists.swift.org/mailman/listinfo/swift-evolution 
>>> <https://lists.swift.org/mailman/listinfo/swift-evolution>
>> 
> 
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

Attachment: signature.asc
Description: Message signed with OpenPGP using GPGMail

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

Reply via email to