That makes sense. Thanks for sharing your reasoning. On Thu, Jun 2, 2016 at 1:38 PM, John McCall <rjmcc...@apple.com> wrote:
> On Jun 2, 2016, at 11:55 AM, Austin Zheng <austinzh...@gmail.com> wrote: > I think we should actually go further. > > If this proposal is accepted, disallow "as" as a way of specifying the > type to construct from a literal. > > > I see no reason to restrict "as" like this. We're not going to stop using > type context as a way of determining the type of a literal, and "as" is a > general feature for providing type context. > > If this proposal isn't accepted, disallow using literal values as the > argument to one-unlabeled-argument constructors. > > > I can't imagine accepting this, either; it would be a major regression in > the usefulness of unlabeled initializers. At best, this would be > appropriate only when the type conforms to an appropriate literal protocol. > > In general, Swift gives unlabeled initializers an idiomatic meaning: they > coerce the argument to the target type in a nominally value-preserving > way. One way of viewing this proposal is that it recognizes that there is > an obvious way to do that when the target type supports being directly > formed from the given kind of literal. But if the target type doesn't > support that, coercing a value of some other appropriate literal type is > still a completely reasonable behavior. > > John. > > > Austin > > On Thu, Jun 2, 2016 at 11:46 AM, Austin Zheng <austinzh...@gmail.com> > 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. >> >> 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 < >> 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 >>> https://lists.swift.org/mailman/listinfo/swift-evolution >>> >>> >> > >
_______________________________________________ swift-evolution mailing list swift-evolution@swift.org https://lists.swift.org/mailman/listinfo/swift-evolution