> On Jun 7, 2016, at 4:25 PM, Dave Abrahams <[email protected]> wrote: > on Tue Jun 07 2016, John McCall <rjmccall-AT-apple.com> wrote: > >>> On Jun 5, 2016, at 5:18 PM, Dave Abrahams via swift-evolution >>> <[email protected]> wrote: >>> on Thu Jun 02 2016, John McCall <[email protected] >>> <mailto:[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. >>> >>> I realize this is somewhat tangential, but... IMO this may not be entirely >>> about literals. >>> >>> We have a standard that full-width type conversions are written as a >>> label-free initializer >>> <https://swift.org/documentation/api-design-guidelines/#type-conversion >>> <https://swift.org/documentation/api-design-guidelines/#type-conversion>>. >>> I believe that is partly responsible for setting up the expectation that >>> Int(42) works as one would expect. It gets ultra-weird when you can >>> convert from type A to type B using B(someA) but you can't write >>> B(someB). We should automatically generate a label-free “copy >>> initializer” for value types, to complete implementation of the expected >>> mental model. >> >> That may also be a good idea, but it won't magically be preferred for >> literal construction if the type has any other constructors of >> literal-convertible type. > > > I know. I'm saying, fixing this for literals without giving value types > copy initializers leaves us with only a partial realization of a larger > mental model to which I believe people are programming.
That's fair. Would you like me to incorporate that into my proposal, then? I see the relation, but it's a pretty significant jump in scope. John. > >> >>> >>>> 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 >>>> >>> >>> -- >>> -Dave >>> >>> _______________________________________________ >>> swift-evolution mailing list >>> [email protected] <mailto:[email protected]> >>> https://lists.swift.org/mailman/listinfo/swift-evolution >>> <https://lists.swift.org/mailman/listinfo/swift-evolution> > > -- > Dave _______________________________________________ swift-evolution mailing list [email protected] https://lists.swift.org/mailman/listinfo/swift-evolution
