Re: [swift-evolution] Proposal: 'T(literal)' should construct T using the appropriate literal protocol if possible

2016-06-08 Thread John McCall via swift-evolution
> On Jun 8, 2016, at 11:15 AM, Dave Abrahams  wrote:
> on Wed Jun 08 2016, John McCall  wrote:
> 
>>> On Jun 7, 2016, at 4:25 PM, Dave Abrahams  wrote:
>>> on Tue Jun 07 2016, John McCall  wrote:
>>> 
> On Jun 5, 2016, at 5:18 PM, Dave Abrahams via swift-evolution 
>  wrote:
> on Thu Jun 02 2016, John McCall  > 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
>  >.
> 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.
> 
> I'm not sure it should be in the same proposal; I just want it to be a
> part of the discussion.  We should be able to make incremental progress,
> but let's make sure we understand how our changes fit into the big picture.

Sure thing.  I agree that that is an interesting way of conceptualizing how
this proposal works, at least for value types where the initializer is 
synthesized:
you could think of it as saying that there's a rule to prefer the "copy 
initializer"
when the argument is a literal and the type is literally constructible.

The flip side is that that argument wouldn't apply to class types or 
(presumably)
generic type parameters, but we'd still want e.g. T(1) to work if T: 
IntegerLiteralConvertible.

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


Re: [swift-evolution] Proposal: 'T(literal)' should construct T using the appropriate literal protocol if possible

2016-06-08 Thread Dave Abrahams via swift-evolution

on Wed Jun 08 2016, John McCall  wrote:

>> On Jun 7, 2016, at 4:25 PM, Dave Abrahams  wrote:
>> on Tue Jun 07 2016, John McCall  wrote:
>> 
 On Jun 5, 2016, at 5:18 PM, Dave Abrahams via swift-evolution 
  wrote:
 on Thu Jun 02 2016, John McCall > 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
 >.
 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.

I'm not sure it should be in the same proposal; I just want it to be a
part of the discussion.  We should be able to make incremental progress,
but let's make sure we understand how our changes fit into the big picture.

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


Re: [swift-evolution] Proposal: 'T(literal)' should construct T using the appropriate literal protocol if possible

2016-06-08 Thread John McCall via swift-evolution
> On Jun 7, 2016, at 4:25 PM, Dave Abrahams  wrote:
> on Tue Jun 07 2016, John McCall  wrote:
> 
>>> On Jun 5, 2016, at 5:18 PM, Dave Abrahams via swift-evolution 
>>>  wrote:
>>> on Thu Jun 02 2016, John McCall >> > 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
>>> >> >.
>>> 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([]) 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
 
>>> 
>>> -- 
>>> -Dave

Re: [swift-evolution] Proposal: 'T(literal)' should construct T using the appropriate literal protocol if possible

2016-06-07 Thread Dave Abrahams via swift-evolution

on Tue Jun 07 2016, John McCall  wrote:

>> On Jun 5, 2016, at 5:18 PM, Dave Abrahams via swift-evolution 
>>  wrote:
>> on Thu Jun 02 2016, John McCall > > 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
>> > >.
>> 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.

>
>> 
>>> 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([]) 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
>>> 
>> 
>> -- 
>> -Dave
>> 
>> ___
>> swift-evolution mailing list
>> swift-evolution@swift.org 
>> https://lists.swift.org/mailman/listinfo/swift-evolution 
>> 

-- 
Dave

Re: [swift-evolution] Proposal: 'T(literal)' should construct T using the appropriate literal protocol if possible

2016-06-07 Thread John McCall via swift-evolution
> On Jun 4, 2016, at 11:54 AM, Chris Lattner  wrote:
> On Jun 2, 2016, at 9:08 AM, John McCall via swift-evolution 
> > 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.
> 
> I completely agree that this is a problem that we need to solve.  In addition 
> to the trap of using [U]Int64 values on 32-bit targets, it is embarrassing 
> that we reject (on all targets):
> 
>   let x = UInt64(0x8000___)
> 
> and require people to use the less obvious syntax:
> 
>   let x = 0x1000___ as UInt64
> 
>> Therefore, I propose that we adopt the following typing rule:
> 
> I’m sorry of this has already been covered down-thread (just getting caught 
> up now, and haven’t read it all), but this seems like a LOT of magic in the 
> type checker to solve this problem.

It was somewhat covered elsewhere in the thread, but this particular idea is 
new, I think.

> Can’t we just require that literal convertibles implement an initializer that 
> the type checker will already consider to be more specific than any of the 
> other overloads?  This would eliminate the need for magic like this in the 
> type checker.  Right now, we have this:
> 
> public protocol IntegerLiteralConvertible {
>   associatedtype IntegerLiteralType : _BuiltinIntegerLiteralConvertible
>   init(integerLiteral value: IntegerLiteralType)
> }
> 
> Change it to be an unlabeled requirement like this probably isn’t enough to 
> make it privileged in the case of ambiguity:

Right.

> public protocol IntegerLiteralConvertible {
>   associatedtype IntegerLiteralType : _BuiltinIntegerLiteralConvertible
>   init(_ value: IntegerLiteralType)
> }
> 
> but perhaps we could have:
> 
> public protocol IntegerLiteralConvertible {
>   associatedtype IntegerLiteralType : _BuiltinIntegerLiteralConvertible
>   init(integerLiteral value: IntegerLiteralType)
>   init(_ value: T)
> }
> 
> and get the type checker to consider the later one to be a“more specific” 
> match than the other overloads, when confronted with a literal?

Er.  We definitely don't want to say that every integer-literal-convertible 
type has to be initializable from an arbitrary value of an arbitrary other 
integer-literal-convertible type.  That's not an implementable requirement, nor 
should it be.

The idea of making a special unlabelled initializer that's preferred by the 
type-checker came up earlier in the thread; the more workable proposals 
included declaring it with @literal or changing the type to some magic 
Literal type.  I just don't think it's a good idea because it's still 
basically the same type-checker magic on the expression side to recognize that 
we should favor the case, and then it adds extra complexity on the declaration 
side; plus the different literal protocols start to interfere with each other 
if one type implements more than one of them.

If you're worried about the complexity of adding new constraints, we could 
start with a more modest rule that only applies the special case when the 
callee is syntactically a type reference rather than e.g. an arbitrary 
expression of metatype value.  But changing the ambiguity-resolution rules is 
actually a lot more complex than just adding a new constraint.

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


Re: [swift-evolution] Proposal: 'T(literal)' should construct T using the appropriate literal protocol if possible

2016-06-07 Thread John McCall via swift-evolution
> On Jun 5, 2016, at 5:18 PM, Dave Abrahams via swift-evolution 
>  wrote:
> on Thu Jun 02 2016, John McCall  > 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
>  >.
> 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.

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([]) 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
>> 
> 
> -- 
> -Dave
> 
> ___
> 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


Re: [swift-evolution] Proposal: 'T(literal)' should construct T using the appropriate literal protocol if possible

2016-06-05 Thread Dave Abrahams via swift-evolution

on Thu Jun 02 2016, John McCall  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
.
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.

> 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([]) 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
>

-- 
-Dave

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


Re: [swift-evolution] Proposal: 'T(literal)' should construct T using the appropriate literal protocol if possible

2016-06-04 Thread Chris Lattner via swift-evolution
On Jun 2, 2016, at 9:08 AM, John McCall via swift-evolution 
 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.

I completely agree that this is a problem that we need to solve.  In addition 
to the trap of using [U]Int64 values on 32-bit targets, it is embarrassing that 
we reject (on all targets):

let x = UInt64(0x8000___)

and require people to use the less obvious syntax:

let x = 0x1000___ as UInt64

> Therefore, I propose that we adopt the following typing rule:

I’m sorry of this has already been covered down-thread (just getting caught up 
now, and haven’t read it all), but this seems like a LOT of magic in the type 
checker to solve this problem.

Can’t we just require that literal convertibles implement an initializer that 
the type checker will already consider to be more specific than any of the 
other overloads?  This would eliminate the need for magic like this in the type 
checker.  Right now, we have this:

public protocol IntegerLiteralConvertible {
  associatedtype IntegerLiteralType : _BuiltinIntegerLiteralConvertible
  init(integerLiteral value: IntegerLiteralType)
}

Change it to be an unlabeled requirement like this probably isn’t enough to 
make it privileged in the case of ambiguity:

public protocol IntegerLiteralConvertible {
  associatedtype IntegerLiteralType : _BuiltinIntegerLiteralConvertible
  init(_ value: IntegerLiteralType)
}

but perhaps we could have:

public protocol IntegerLiteralConvertible {
  associatedtype IntegerLiteralType : _BuiltinIntegerLiteralConvertible
  init(integerLiteral value: IntegerLiteralType)
  init(_ value: T)
}

and get the type checker to consider the later one to be a“more specific” match 
than the other overloads, when confronted with a literal?

-Chris

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


Re: [swift-evolution] Proposal: 'T(literal)' should construct T using the appropriate literal protocol if possible

2016-06-04 Thread Matthew Johnson via swift-evolution

> On Jun 4, 2016, at 10:27 AM, LM  wrote:
> 
> 
> 
> On Jun 4, 2016, at 4:00 PM, Matthew Johnson via swift-evolution 
> > wrote:
> 
>> 
>>> On Jun 3, 2016, at 9:30 PM, John McCall >> > wrote:
>>> 
 On Jun 3, 2016, at 7:08 PM, Matthew Johnson > wrote:
> On Jun 3, 2016, at 8:11 PM, John McCall  > wrote:
> 
>> On Jun 3, 2016, at 5:13 PM, Matthew Johnson > > wrote:
>> On Jun 3, 2016, at 6:23 PM, John McCall > > wrote:
>> 
> On Jun 3, 2016, at 4:07 PM, David Sweeris  > wrote:
> On Jun 3, 2016, at 16:17, Matthew Johnson via swift-evolution 
> > wrote:
> 
> Using an external parameter label in a declaration and allowing it to 
> be omitted at the call site does not feel like the right answer to 
> me.  I think we can find a better way to present this syntactically.
 
 +eleventy gajillion
>>> 
>>> I'm actually quite happy with the user-facing aspects of the current 
>>> literal protocols and see zero reason to update them for this, so if 
>>> that's the choice, I'll just leave this aside.
>> 
>> Are you suggesting that preserving the current syntax of the literal 
>> protocols is more important than fixing this behavior so it works like 
>> most people seem to expect?  Why not be open to other syntactic 
>> solutions? 
> 
> I think fixing the behavior is good, and I stand by this proposal.  
 
 I agree fixing it is good and we should do it.  I’m just trying to explore 
 the solution space to see if there are any alternatives that might be more 
 appealing.  Clearly you’ve thought about this a lot but it’s a new topic 
 to consider for the rest of us.  :)
>>> 
>>> I'm sorry if I've come across as frustrated.  It's easy for me to forget 
>>> that things that I consider well-settled haven't always been covered in 
>>> depth here.  The community is not intentionally re-inventing things for no 
>>> purpose, it's making a genuine effort to explore the constraints on a part 
>>> of the language that it isn't familiar with the rationale for.
>> 
>> No problem.  I know it’s not fun to revisit hard-thought decisions that 
>> you’re happy with! :)  And I can see how it feels like we’re trying to do 
>> that here.  That said, these discussions are the best way for the community 
>> to become familiar with some of the rationale for the way things currently 
>> are.  :)
> 
> I find It helps to read the docs that has been produced (not all up to date 
> but still rich in background data). The source code is also a great place to 
> do a reality chk on ideas. 

Agree.  I have read most of the docs found here: 
https://github.com/apple/swift/tree/master/docs 
.  But docs can only cover so 
much.  A lot of knowledge is often shared communally, but not explicitly 
documented.

> 
> @john thank you for taking the time to share.
> 
> 
>> 
>>> 
> There is, however, nothing glaringly wrong with the literal protocols.  
> They do not need to redesigned simply because we found a syntactic 
> interaction that needs to be cleaned up.
> 
> There are good reasons the protocols have evolved the way they have.  The 
> labels clearly mark the purpose of each initializer and distinguish one 
> from another on types that support multiple literal kinds.  The labels 
> also clearly indicate that the initializers are not intended for general 
> use.  The argument(s) to the initializer do not always represent a single 
> value of literal type.  Some protocols provide multiple initializers, and 
> it is quite possible that that will become gradually more common as we 
> explore ways to grant more flexibility to code outside of the standard 
> library.  And we actually consider it good that you can invoke these 
> initializers explicitly; it's only accidental use that we feel it's 
> important to avoid, which labels provide excellent protection against.
 
 If it is important that these initializers be callable directly I suppose 
 the label is the only way to go.  I can’t think of a reason why this is 
 necessary though.  I would consider it bad design for a type that expects 
 to be initialized with an Int variable to require its callers to use the 
 label, as opposed to providing an alternate initializer that doesn’t have 
 a label with “literal” in its name.  Are there specific 

Re: [swift-evolution] Proposal: 'T(literal)' should construct T using the appropriate literal protocol if possible

2016-06-04 Thread LM via swift-evolution


> On Jun 4, 2016, at 4:00 PM, Matthew Johnson via swift-evolution 
>  wrote:
> 
> 
>>> On Jun 3, 2016, at 9:30 PM, John McCall  wrote:
>>> 
 On Jun 3, 2016, at 7:08 PM, Matthew Johnson  wrote:
> On Jun 3, 2016, at 8:11 PM, John McCall  wrote:
> 
> On Jun 3, 2016, at 5:13 PM, Matthew Johnson  
> wrote:
> On Jun 3, 2016, at 6:23 PM, John McCall  wrote:
> 
 On Jun 3, 2016, at 4:07 PM, David Sweeris  wrote:
 On Jun 3, 2016, at 16:17, Matthew Johnson via swift-evolution 
  wrote:
 
 Using an external parameter label in a declaration and allowing it to 
 be omitted at the call site does not feel like the right answer to me. 
  I think we can find a better way to present this syntactically.
>>> 
>>> +eleventy gajillion
>> 
>> I'm actually quite happy with the user-facing aspects of the current 
>> literal protocols and see zero reason to update them for this, so if 
>> that's the choice, I'll just leave this aside.
> 
> Are you suggesting that preserving the current syntax of the literal 
> protocols is more important than fixing this behavior so it works like 
> most people seem to expect?  Why not be open to other syntactic 
> solutions? 
 
 I think fixing the behavior is good, and I stand by this proposal.  
>>> 
>>> I agree fixing it is good and we should do it.  I’m just trying to explore 
>>> the solution space to see if there are any alternatives that might be more 
>>> appealing.  Clearly you’ve thought about this a lot but it’s a new topic to 
>>> consider for the rest of us.  :)
>> 
>> I'm sorry if I've come across as frustrated.  It's easy for me to forget 
>> that things that I consider well-settled haven't always been covered in 
>> depth here.  The community is not intentionally re-inventing things for no 
>> purpose, it's making a genuine effort to explore the constraints on a part 
>> of the language that it isn't familiar with the rationale for.
> 
> No problem.  I know it’s not fun to revisit hard-thought decisions that 
> you’re happy with! :)  And I can see how it feels like we’re trying to do 
> that here.  That said, these discussions are the best way for the community 
> to become familiar with some of the rationale for the way things currently 
> are.  :)

I find It helps to read the docs that has been produced (not all up to date but 
still rich in background data). The source code is also a great place to do a 
reality chk on ideas. 

@john thank you for taking the time to share.


> 
>> 
 There is, however, nothing glaringly wrong with the literal protocols.  
 They do not need to redesigned simply because we found a syntactic 
 interaction that needs to be cleaned up.
 
 There are good reasons the protocols have evolved the way they have.  The 
 labels clearly mark the purpose of each initializer and distinguish one 
 from another on types that support multiple literal kinds.  The labels 
 also clearly indicate that the initializers are not intended for general 
 use.  The argument(s) to the initializer do not always represent a single 
 value of literal type.  Some protocols provide multiple initializers, and 
 it is quite possible that that will become gradually more common as we 
 explore ways to grant more flexibility to code outside of the standard 
 library.  And we actually consider it good that you can invoke these 
 initializers explicitly; it's only accidental use that we feel it's 
 important to avoid, which labels provide excellent protection against.
>>> 
>>> If it is important that these initializers be callable directly I suppose 
>>> the label is the only way to go.  I can’t think of a reason why this is 
>>> necessary though.  I would consider it bad design for a type that expects 
>>> to be initialized with an Int variable to require its callers to use the 
>>> label, as opposed to providing an alternate initializer that doesn’t have a 
>>> label with “literal” in its name.  Are there specific use cases where you 
>>> think this capability is important or is it just the principle that you 
>>> should be able to call any initializer you write?
>> 
>> Partly that principle, but partly the ability to forward 
>> literal-initialization.  You can forward literal-initialization to, say, a 
>> BuiltinIntegerLiteralConvertible type by just appointing it your associated 
>> IntegerLiteralType, but if you're wrapping another type, that doesn't work.  
>> For example:
>> 
>>  struct MyValue : IntegerLiteralConvertible {
>>init(integerLiteral literal: JSONValue.IntegerLiteralType) {
>>  json = JSONValue(integerLiteral: literal)
>>}
>>...
>>  }
> 
> What is the advantage of calling the 

Re: [swift-evolution] Proposal: 'T(literal)' should construct T using the appropriate literal protocol if possible

2016-06-04 Thread Matthew Johnson via swift-evolution

> On Jun 3, 2016, at 9:30 PM, John McCall  wrote:
> 
>> On Jun 3, 2016, at 7:08 PM, Matthew Johnson  wrote:
>>> On Jun 3, 2016, at 8:11 PM, John McCall  wrote:
>>> 
 On Jun 3, 2016, at 5:13 PM, Matthew Johnson  wrote:
 On Jun 3, 2016, at 6:23 PM, John McCall  wrote:
 
>>> On Jun 3, 2016, at 4:07 PM, David Sweeris  wrote:
>>> On Jun 3, 2016, at 16:17, Matthew Johnson via swift-evolution 
>>>  wrote:
>>> 
>>> Using an external parameter label in a declaration and allowing it to 
>>> be omitted at the call site does not feel like the right answer to me.  
>>> I think we can find a better way to present this syntactically.
>> 
>> +eleventy gajillion
> 
> I'm actually quite happy with the user-facing aspects of the current 
> literal protocols and see zero reason to update them for this, so if 
> that's the choice, I'll just leave this aside.
 
 Are you suggesting that preserving the current syntax of the literal 
 protocols is more important than fixing this behavior so it works like 
 most people seem to expect?  Why not be open to other syntactic solutions? 
>>> 
>>> I think fixing the behavior is good, and I stand by this proposal.  
>> 
>> I agree fixing it is good and we should do it.  I’m just trying to explore 
>> the solution space to see if there are any alternatives that might be more 
>> appealing.  Clearly you’ve thought about this a lot but it’s a new topic to 
>> consider for the rest of us.  :)
> 
> I'm sorry if I've come across as frustrated.  It's easy for me to forget that 
> things that I consider well-settled haven't always been covered in depth 
> here.  The community is not intentionally re-inventing things for no purpose, 
> it's making a genuine effort to explore the constraints on a part of the 
> language that it isn't familiar with the rationale for.

No problem.  I know it’s not fun to revisit hard-thought decisions that you’re 
happy with! :)  And I can see how it feels like we’re trying to do that here.  
That said, these discussions are the best way for the community to become 
familiar with some of the rationale for the way things currently are.  :)

> 
>>> There is, however, nothing glaringly wrong with the literal protocols.  
>>> They do not need to redesigned simply because we found a syntactic 
>>> interaction that needs to be cleaned up.
>>> 
>>> There are good reasons the protocols have evolved the way they have.  The 
>>> labels clearly mark the purpose of each initializer and distinguish one 
>>> from another on types that support multiple literal kinds.  The labels also 
>>> clearly indicate that the initializers are not intended for general use.  
>>> The argument(s) to the initializer do not always represent a single value 
>>> of literal type.  Some protocols provide multiple initializers, and it is 
>>> quite possible that that will become gradually more common as we explore 
>>> ways to grant more flexibility to code outside of the standard library.  
>>> And we actually consider it good that you can invoke these initializers 
>>> explicitly; it's only accidental use that we feel it's important to avoid, 
>>> which labels provide excellent protection against.
>> 
>> If it is important that these initializers be callable directly I suppose 
>> the label is the only way to go.  I can’t think of a reason why this is 
>> necessary though.  I would consider it bad design for a type that expects to 
>> be initialized with an Int variable to require its callers to use the label, 
>> as opposed to providing an alternate initializer that doesn’t have a label 
>> with “literal” in its name.  Are there specific use cases where you think 
>> this capability is important or is it just the principle that you should be 
>> able to call any initializer you write?
> 
> Partly that principle, but partly the ability to forward 
> literal-initialization.  You can forward literal-initialization to, say, a 
> BuiltinIntegerLiteralConvertible type by just appointing it your associated 
> IntegerLiteralType, but if you're wrapping another type, that doesn't work.  
> For example:
> 
>  struct MyValue : IntegerLiteralConvertible {
>init(integerLiteral literal: JSONValue.IntegerLiteralType) {
>  json = JSONValue(integerLiteral: literal)
>}
>...
>  }

What is the advantage of calling the literal JSONValue initializer here rather 
than a non-literal initializer that accepts JSONValue.IntegerLiteralType?  Is 
there something in the implementation that makes this more efficient?

If forwarding is the intended use for explicit calls, wouldn’t the `@literal` 
attribute attached to the type be an alternative way to address the forwarding 
use case?

Are there any non-forwarding use cases for explicit calls?

If forwarding is the only intended use 

Re: [swift-evolution] Proposal: 'T(literal)' should construct T using the appropriate literal protocol if possible

2016-06-03 Thread John McCall via swift-evolution
> On Jun 3, 2016, at 8:11 PM, Ben Rimmington  wrote:
> I think your original proposal is good, but just in case:
> 
> [Currently]
> 
>// Literal `7` is converted to `Swift.IntegerLiteralType` typealias.
>UInt16(7) calls UInt16.init(_ value: Int)
> 
> [Suggested]
> 
>// Literal `7` is converted to `UInt16.IntegerLiteralType` associatedtype.
>UInt16(7) calls UInt16.init(_ value: UInt16)
> 
> Have "user-defined literals" already been rejected for Swift?
> 
> 

I don't know that we've ruled out using literal suffixes, but it's not really 
relevant.
We already have a syntax for coercing a literal to a specific type; the problem 
is
that people are writing UInt8(7) anyway, and it's completely reasonable for them
to expect that to work.  So even if we added user-defined literal suffixes as a
feature, we'd still have this problem.

I can imagine Swift adding literal suffixes, but only to enable a units 
library, not
to provide yet another way to specify type widths.

John.


> 
> -- Ben
> 
>> On 4 Jun 2016, at 02:20, John McCall  wrote:
>> 
>>> On Jun 3, 2016, at 5:31 PM, Ben Rimmington via swift-evolution 
>>>  wrote:
>>> John McCall wrote:
>>> 
 I think that's a very promising way of thinking about literals.  Writing
 a literal creates a notional value whose type is the informal, infinite-
 precise type of all integer/FP/collection/etc. literals, which (1) can be
 implicitly converted to any type that implements the appropriate protocol
 and (2) in fact *must* be converted to some such type (possibly the
 default type for that literal) in order for the code to be executable.
>>> 
>>> Could you allow IntegerLiteralConvertible.IntegerLiteralType associatedtype
>>> to override the default Swift.IntegerLiteralType typealias iff there's more
>>> than one unlabelled init(_:) to choose from? Then you can call the "correct"
>>> init(_:) instead of calling init(integerLiteral:) as a "special case".
>> 
>> This is essentially already how it works.  The literal protocols are not 
>> invoked via
>> overload resolution; Swift always invokes the initializer that satisfies the 
>> protocol
>> requirement.
>> 
>> That is, you can provide ten different init(integerLiteral: T) initializers, 
>> but that will
>> just prevent the compiler from inferring the associated type, so you'll have 
>> to
>> declare it.  Once you do, that associated type will determine the 
>> initializer that
>> satisfies the requirement, and that'll always be the initializer chosen.
>> 
>> John.
> 

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


Re: [swift-evolution] Proposal: 'T(literal)' should construct T using the appropriate literal protocol if possible

2016-06-03 Thread John McCall via swift-evolution
> On Jun 3, 2016, at 7:08 PM, Matthew Johnson  wrote:
>> On Jun 3, 2016, at 8:11 PM, John McCall  wrote:
>> 
>>> On Jun 3, 2016, at 5:13 PM, Matthew Johnson  wrote:
>>> On Jun 3, 2016, at 6:23 PM, John McCall  wrote:
>>> 
>> On Jun 3, 2016, at 4:07 PM, David Sweeris  wrote:
>> On Jun 3, 2016, at 16:17, Matthew Johnson via swift-evolution 
>>  wrote:
>> 
>> Using an external parameter label in a declaration and allowing it to be 
>> omitted at the call site does not feel like the right answer to me.  I 
>> think we can find a better way to present this syntactically.
> 
> +eleventy gajillion
 
 I'm actually quite happy with the user-facing aspects of the current 
 literal protocols and see zero reason to update them for this, so if 
 that's the choice, I'll just leave this aside.
>>> 
>>> Are you suggesting that preserving the current syntax of the literal 
>>> protocols is more important than fixing this behavior so it works like most 
>>> people seem to expect?  Why not be open to other syntactic solutions? 
>> 
>> I think fixing the behavior is good, and I stand by this proposal.  
> 
> I agree fixing it is good and we should do it.  I’m just trying to explore 
> the solution space to see if there are any alternatives that might be more 
> appealing.  Clearly you’ve thought about this a lot but it’s a new topic to 
> consider for the rest of us.  :)

I'm sorry if I've come across as frustrated.  It's easy for me to forget that 
things that I consider well-settled haven't always been covered in depth here.  
The community is not intentionally re-inventing things for no purpose, it's 
making a genuine effort to explore the constraints on a part of the language 
that it isn't familiar with the rationale for.

>> There is, however, nothing glaringly wrong with the literal protocols.  They 
>> do not need to redesigned simply because we found a syntactic interaction 
>> that needs to be cleaned up.
>> 
>> There are good reasons the protocols have evolved the way they have.  The 
>> labels clearly mark the purpose of each initializer and distinguish one from 
>> another on types that support multiple literal kinds.  The labels also 
>> clearly indicate that the initializers are not intended for general use.  
>> The argument(s) to the initializer do not always represent a single value of 
>> literal type.  Some protocols provide multiple initializers, and it is quite 
>> possible that that will become gradually more common as we explore ways to 
>> grant more flexibility to code outside of the standard library.  And we 
>> actually consider it good that you can invoke these initializers explicitly; 
>> it's only accidental use that we feel it's important to avoid, which labels 
>> provide excellent protection against.
> 
> If it is important that these initializers be callable directly I suppose the 
> label is the only way to go.  I can’t think of a reason why this is necessary 
> though.  I would consider it bad design for a type that expects to be 
> initialized with an Int variable to require its callers to use the label, as 
> opposed to providing an alternate initializer that doesn’t have a label with 
> “literal” in its name.  Are there specific use cases where you think this 
> capability is important or is it just the principle that you should be able 
> to call any initializer you write?

Partly that principle, but partly the ability to forward 
literal-initialization.  You can forward literal-initialization to, say, a 
BuiltinIntegerLiteralConvertible type by just appointing it your associated 
IntegerLiteralType, but if you're wrapping another type, that doesn't work.  
For example:

  struct MyValue : IntegerLiteralConvertible {
init(integerLiteral literal: JSONValue.IntegerLiteralType) {
  json = JSONValue(integerLiteral: literal)
}
...
  }

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


Re: [swift-evolution] Proposal: 'T(literal)' should construct T using the appropriate literal protocol if possible

2016-06-03 Thread Matthew Johnson via swift-evolution

> On Jun 3, 2016, at 8:11 PM, John McCall  wrote:
> 
>> On Jun 3, 2016, at 5:13 PM, Matthew Johnson  wrote:
>> On Jun 3, 2016, at 6:23 PM, John McCall  wrote:
>> 
> On Jun 3, 2016, at 4:07 PM, David Sweeris  wrote:
> On Jun 3, 2016, at 16:17, Matthew Johnson via swift-evolution 
>  wrote:
> 
> Using an external parameter label in a declaration and allowing it to be 
> omitted at the call site does not feel like the right answer to me.  I 
> think we can find a better way to present this syntactically.
 
 +eleventy gajillion
>>> 
>>> I'm actually quite happy with the user-facing aspects of the current 
>>> literal protocols and see zero reason to update them for this, so if that's 
>>> the choice, I'll just leave this aside.
>> 
>> Are you suggesting that preserving the current syntax of the literal 
>> protocols is more important than fixing this behavior so it works like most 
>> people seem to expect?  Why not be open to other syntactic solutions? 
> 
> I think fixing the behavior is good, and I stand by this proposal.  

I agree fixing it is good and we should do it.  I’m just trying to explore the 
solution space to see if there are any alternatives that might be more 
appealing.  Clearly you’ve thought about this a lot but it’s a new topic to 
consider for the rest of us.  :)

> There is, however, nothing glaringly wrong with the literal protocols.  They 
> do not need to redesigned simply because we found a syntactic interaction 
> that needs to be cleaned up.
> 
> There are good reasons the protocols have evolved the way they have.  The 
> labels clearly mark the purpose of each initializer and distinguish one from 
> another on types that support multiple literal kinds.  The labels also 
> clearly indicate that the initializers are not intended for general use.  The 
> argument(s) to the initializer do not always represent a single value of 
> literal type.  Some protocols provide multiple initializers, and it is quite 
> possible that that will become gradually more common as we explore ways to 
> grant more flexibility to code outside of the standard library.  And we 
> actually consider it good that you can invoke these initializers explicitly; 
> it's only accidental use that we feel it's important to avoid, which labels 
> provide excellent protection against.

If it is important that these initializers be callable directly I suppose the 
label is the only way to go.  I can’t think of a reason why this is necessary 
though.  I would consider it bad design for a type that expects to be 
initialized with an Int variable to require its callers to use the label, as 
opposed to providing an alternate initializer that doesn’t have a label with 
“literal” in its name.  Are there specific use cases where you think this 
capability is important or is it just the principle that you should be able to 
call any initializer you write?

-Matthew

> 
> If you have specific criticisms of any of the literal protocols, e.g. you 
> find them limiting or non-performant for your own types, then you are welcome 
> to raise them here.  However, resemblance to actual literal syntax has never 
> been a design goal for the literal protocols; and besides, this will always 
> be a secondary literal syntax, one far less important than contextual typing.
> 
> John.

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


Re: [swift-evolution] Proposal: 'T(literal)' should construct T using the appropriate literal protocol if possible

2016-06-03 Thread John McCall via swift-evolution
> On Jun 3, 2016, at 5:31 PM, Ben Rimmington via swift-evolution 
>  wrote:
> John McCall wrote:
> 
>> I think that's a very promising way of thinking about literals.  Writing
>> a literal creates a notional value whose type is the informal, infinite-
>> precise type of all integer/FP/collection/etc. literals, which (1) can be
>> implicitly converted to any type that implements the appropriate protocol
>> and (2) in fact *must* be converted to some such type (possibly the
>> default type for that literal) in order for the code to be executable.
> 
> Could you allow IntegerLiteralConvertible.IntegerLiteralType associatedtype
> to override the default Swift.IntegerLiteralType typealias iff there's more
> than one unlabelled init(_:) to choose from? Then you can call the "correct"
> init(_:) instead of calling init(integerLiteral:) as a "special case".

This is essentially already how it works.  The literal protocols are not 
invoked via
overload resolution; Swift always invokes the initializer that satisfies the 
protocol
requirement.

That is, you can provide ten different init(integerLiteral: T) initializers, 
but that will
just prevent the compiler from inferring the associated type, so you'll have to
declare it.  Once you do, that associated type will determine the initializer 
that
satisfies the requirement, and that'll always be the initializer chosen.

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


Re: [swift-evolution] Proposal: 'T(literal)' should construct T using the appropriate literal protocol if possible

2016-06-03 Thread John McCall via swift-evolution
> On Jun 3, 2016, at 5:13 PM, Matthew Johnson  wrote:
> On Jun 3, 2016, at 6:23 PM, John McCall  wrote:
> 
 On Jun 3, 2016, at 4:07 PM, David Sweeris  wrote:
 On Jun 3, 2016, at 16:17, Matthew Johnson via swift-evolution 
  wrote:
 
 Using an external parameter label in a declaration and allowing it to be 
 omitted at the call site does not feel like the right answer to me.  I 
 think we can find a better way to present this syntactically.
>>> 
>>> +eleventy gajillion
>> 
>> I'm actually quite happy with the user-facing aspects of the current literal 
>> protocols and see zero reason to update them for this, so if that's the 
>> choice, I'll just leave this aside.
> 
> Are you suggesting that preserving the current syntax of the literal 
> protocols is more important than fixing this behavior so it works like most 
> people seem to expect?  Why not be open to other syntactic solutions? 

I think fixing the behavior is good, and I stand by this proposal.  There is, 
however, nothing glaringly wrong with the literal protocols.  They do not need 
to redesigned simply because we found a syntactic interaction that needs to be 
cleaned up.

There are good reasons the protocols have evolved the way they have.  The 
labels clearly mark the purpose of each initializer and distinguish one from 
another on types that support multiple literal kinds.  The labels also clearly 
indicate that the initializers are not intended for general use.  The 
argument(s) to the initializer do not always represent a single value of 
literal type.  Some protocols provide multiple initializers, and it is quite 
possible that that will become gradually more common as we explore ways to 
grant more flexibility to code outside of the standard library.  And we 
actually consider it good that you can invoke these initializers explicitly; 
it's only accidental use that we feel it's important to avoid, which labels 
provide excellent protection against.

If you have specific criticisms of any of the literal protocols, e.g. you find 
them limiting or non-performant for your own types, then you are welcome to 
raise them here.  However, resemblance to actual literal syntax has never been 
a design goal for the literal protocols; and besides, this will always be a 
secondary literal syntax, one far less important than contextual typing.

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


Re: [swift-evolution] Proposal: 'T(literal)' should construct T using the appropriate literal protocol if possible

2016-06-03 Thread Ben Rimmington via swift-evolution
John McCall wrote:

> I think that's a very promising way of thinking about literals.  Writing
> a literal creates a notional value whose type is the informal, infinite-
> precise type of all integer/FP/collection/etc. literals, which (1) can be
> implicitly converted to any type that implements the appropriate protocol
> and (2) in fact *must* be converted to some such type (possibly the
> default type for that literal) in order for the code to be executable.

Could you allow IntegerLiteralConvertible.IntegerLiteralType associatedtype
to override the default Swift.IntegerLiteralType typealias iff there's more
than one unlabelled init(_:) to choose from? Then you can call the "correct"
init(_:) instead of calling init(integerLiteral:) as a "special case".

[stdlib/public/core/CompilerProtocols.swift]

/// Conforming types can be initialized with integer literals.
public protocol IntegerLiteralConvertible {
associatedtype IntegerLiteralType : _BuiltinIntegerLiteralConvertible
/// Create an instance initialized to `value`.
init(integerLiteral value: IntegerLiteralType)
}

[stdlib/public/core/Policy.swift]

/// The default type for an otherwise-unconstrained integer literal.
public typealias IntegerLiteralType = Int

-- Ben


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


Re: [swift-evolution] Proposal: 'T(literal)' should construct T using the appropriate literal protocol if possible

2016-06-03 Thread Matthew Johnson via swift-evolution


Sent from my iPad

On Jun 3, 2016, at 6:23 PM, John McCall  wrote:

>>> On Jun 3, 2016, at 4:07 PM, David Sweeris  wrote:
>>> On Jun 3, 2016, at 16:17, Matthew Johnson via swift-evolution 
>>>  wrote:
>>> 
>>> Using an external parameter label in a declaration and allowing it to be 
>>> omitted at the call site does not feel like the right answer to me.  I 
>>> think we can find a better way to present this syntactically.
>> 
>> +eleventy gajillion
> 
> I'm actually quite happy with the user-facing aspects of the current literal 
> protocols and see zero reason to update them for this, so if that's the 
> choice, I'll just leave this aside.

Are you suggesting that preserving the current syntax of the literal protocols 
is more important than fixing this behavior so it works like most people seem 
to expect?  Why not be open to other syntactic solutions? 

> 
> John.

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


Re: [swift-evolution] Proposal: 'T(literal)' should construct T using the appropriate literal protocol if possible

2016-06-03 Thread Austin Zheng via swift-evolution
I would be very interested in seeing your original proposal presented
for formal review.

Austin

On 6/3/16, John McCall via swift-evolution  wrote:
>> On Jun 3, 2016, at 4:07 PM, David Sweeris  wrote:
>>> On Jun 3, 2016, at 16:17, Matthew Johnson via swift-evolution
>>>  wrote:
>>>
>>> Using an external parameter label in a declaration and allowing it to be
>>> omitted at the call site does not feel like the right answer to me.  I
>>> think we can find a better way to present this syntactically.
>>
>> +eleventy gajillion
>
> I'm actually quite happy with the user-facing aspects of the current literal
> protocols and see zero reason to update them for this, so if that's the
> choice, I'll just leave this aside.
>
> 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


Re: [swift-evolution] Proposal: 'T(literal)' should construct T using the appropriate literal protocol if possible

2016-06-03 Thread David Sweeris via swift-evolution

> On Jun 3, 2016, at 16:17, Matthew Johnson via swift-evolution 
>  wrote:
> 
> Using an external parameter label in a declaration and allowing it to be 
> omitted at the call site does not feel like the right answer to me.  I think 
> we can find a better way to present this syntactically.

+eleventy gajillion

- Dave Sweeris
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] Proposal: 'T(literal)' should construct T using the appropriate literal protocol if possible

2016-06-03 Thread Brent Royal-Gordon via swift-evolution
> I think our decision should be based upon which syntactic construct feels 
> least inconsistent with other similar syntactic constructs and therefore 
> feels the least arbitrary.  Restricting the usage of a generic `Literal` type 
> to literal convertible initializers feels a little bit less arbitrary than 
> allowing the call site to omit a label, but it feels a little bit more 
> arbitrary than introducing an attribute that has a very specialized context 
> of applicability.

Honestly, I think `@literal` is only "consistent" with the rest of the language 
in that @s are used to mark compiler magic. `Literal<>` is attempting to *not* 
be much more magical than, say, `StringInterpolationConvertible`, where a 
particular syntax generates a certain pattern of calls.

-- 
Brent Royal-Gordon
Architechies

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


Re: [swift-evolution] Proposal: 'T(literal)' should construct T using the appropriate literal protocol if possible

2016-06-03 Thread Matthew Johnson via swift-evolution

> On Jun 3, 2016, at 4:05 PM, Brent Royal-Gordon  wrote:
> 
>> I am not the only one who feels that way.  Quoting Brent:
>> 
>> "But if you're going to call `init(integerLiteral:)` like it's `init(_:)`, I 
>> don't think that's a good idea. Parameter labels are supposed to be 
>> significant; we don't want to lose that.”
>> 
>> I agree with this.  That is the motivation for my suggestion.  I think it’s 
>> at least worth discussing as an alternative to magically allowing an 
>> external parameter label to be omitted.  Brent, what do you think of my 
>> suggestion?
> 
> I think it could be simpler:
> 
>   public struct Literal {
>   public let value: LiteralType
>   internal init(_value value: LiteralType)
>   }
>   
>   public protocol IntegerLiteralConvertible {
>   associatedtype IntegerLiteralType
>   init(_ literal: Literal)
>   }
> 
> Only the standard library can create a Literal, which it would do by 
> constructing the IntegerLiteralType with its magic builtin literal stuff and 
> wrapping it. You still have your magic parameter aspect, but without any 
> actual magic, just access control. 

I like this solution as well as Xiaodi’s `@literal` idea better than the idea I 
came up with.  I think I like `@literal` best because it feels more appropriate 
to restrict an attribute to a specific context (signatures for literal 
convertible initializers) than anything else.  We don’t want to allow this in 
any other signatures and no types are restricted in that way.  The solution I 
came up with has that problem as well as the `#literal` “value” that is also 
restricted unlike other compiler generated values.  

I think our decision should be based upon which syntactic construct feels least 
inconsistent with other similar syntactic constructs and therefore feels the 
least arbitrary.  Restricting the usage of a generic `Literal` type to literal 
convertible initializers feels a little bit less arbitrary than allowing the 
call site to omit a label, but it feels a little bit more arbitrary than 
introducing an attribute that has a very specialized context of applicability.

> 
> -- 
> Brent Royal-Gordon
> Architechies
> 

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


Re: [swift-evolution] Proposal: 'T(literal)' should construct T using the appropriate literal protocol if possible

2016-06-03 Thread Matthew Johnson via swift-evolution

> On Jun 3, 2016, at 3:17 PM, John McCall  wrote:
> 
>> On Jun 3, 2016, at 12:41 PM, Matthew Johnson > > wrote:
>>> On Jun 3, 2016, at 1:36 PM, John McCall >> > wrote:
>>> 
 On Jun 2, 2016, at 6:48 PM, Matthew Johnson > wrote:
 On Jun 2, 2016, at 6:51 PM, John McCall via swift-evolution 
 > wrote:
 
>> On Jun 2, 2016, at 4:33 PM, Xiaodi Wu > > wrote:
>> The IntegerLiteral type idea might be worth exploring. It does seem to 
>> provide some additional consistency. For example, wasn't it clarified on 
>> this list just recently that literals don't have a type and adopt one 
>> based on context? It'd be nice to point out that 42 is an IntegerLiteral 
>> when explaining that it's not an Int.
> 
> I think that's a very promising way of thinking about literals.  Writing 
> a literal creates a notional value whose type is the informal, 
> infinite-precise type of all integer/FP/collection/etc. literals, which 
> (1) can be implicitly converted to any type that implements the 
> appropriate protocol and (2) in fact *must* be converted to some such 
> type (possibly the default type for that literal) in order for the code 
> to be executable.  You can then think about this proposal as saying that 
> an explicit conversion from that informal type to a literal-convertible 
> type follows the same path as an implicit conversion would have.
 
 It sounds like the reason you don't want to remove the label is because it 
 distinguishes the literal initializer and you don't want it called with a 
 variable accidentally right?  
 
 What if we do something like this:
 
 init(_ value: IntegerLiteralType, literal: IntegerLiteral = #literal)
 
 The idea here is that the IntegerLiteral type and friends are special 
 types that have no members and cannot be used except by the literal 
 convertible protocols and their conformances.  There is nothing you can do 
 with the value at all.  
 
 The trick is that by defaulting it to #literal we are indicating the 
 compiler synthesizes the logical value, as with #file, #line, etc.  The 
 compiler would refuse to synthesize this value when a literal is not used. 
  This means it is never selected when the user provides a variable to a 
 converting initializer.  If an independent initializer accepting a value 
 of the same type also exists that would be selected.  However, when a 
 literal *is* used and the type conforms to the relevant literal 
 convertible protocol the compiler always synthesized the value making it 
 always the most specific overload.
 
 Of course no runtime value would actually exist.  This is just a logical 
 value marking the fact that a literal was used to call the initializer.  
 
 This approach solves the same problem while retaining semantic consistency 
 with the language (no label elision or short circuit of overload 
 resolution).  The magic is arguably a lot more restrained - types for 
 which values can only be supplied by the compiler.  We could artificially 
 restrict usage of these types if we wanted to, but we wouldn't have to.  
 Nothing could be accomplished by using the types anywhere else so nobody 
 do so and it wouldn't be actively harmful to allow them to be used 
 anywhere other types can be used.  Only the ability to create values of 
 the type needs to be restricted and we can already write types like that 
 by marking the initializers private.
 
 Any thoughts on this approach?
>>> 
>>> This is still a special-case type-checking rule, which means that it's 
>>> still basically my proposal except, instead of just rewriting the call to 
>>> use a labeled literal initializer, it rewrites the call to use a magic 
>>> initializer which cannot be used by users because it requires arguments 
>>> that users cannot create.  I just don't understand the motivation here.  
>>> It's not a simpler language model to use, explain, or implement; it 
>>> purports to be conceptually simpler and less magical while actually 
>>> inventing two magic new language concepts (IntegerLiteral and #literal) on 
>>> top of the same special cases.
>> 
>> I understand that this is still a special case and also that the 
>> implementation is pretty much identical.  But I think the way it is 
>> presented to users is important. 
>> 
>>  The motivation is to come up with a design that lets us implement your 
>> proposal without magically eliding a parameter label.  There is no other 
>> case in Swift where you can directly call any function 

Re: [swift-evolution] Proposal: 'T(literal)' should construct T using the appropriate literal protocol if possible

2016-06-03 Thread Brent Royal-Gordon via swift-evolution
> I am not the only one who feels that way.  Quoting Brent:
> 
> "But if you're going to call `init(integerLiteral:)` like it's `init(_:)`, I 
> don't think that's a good idea. Parameter labels are supposed to be 
> significant; we don't want to lose that.”
> 
> I agree with this.  That is the motivation for my suggestion.  I think it’s 
> at least worth discussing as an alternative to magically allowing an external 
> parameter label to be omitted.  Brent, what do you think of my suggestion?

I think it could be simpler:

public struct Literal {
public let value: LiteralType
internal init(_value value: LiteralType)
}

public protocol IntegerLiteralConvertible {
associatedtype IntegerLiteralType
init(_ literal: Literal)
}

Only the standard library can create a Literal, which it would do by 
constructing the IntegerLiteralType with its magic builtin literal stuff and 
wrapping it. You still have your magic parameter aspect, but without any actual 
magic, just access control. 

-- 
Brent Royal-Gordon
Architechies

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


Re: [swift-evolution] Proposal: 'T(literal)' should construct T using the appropriate literal protocol if possible

2016-06-03 Thread John McCall via swift-evolution
> On Jun 3, 2016, at 12:41 PM, Matthew Johnson  wrote:
>> On Jun 3, 2016, at 1:36 PM, John McCall > > wrote:
>> 
>>> On Jun 2, 2016, at 6:48 PM, Matthew Johnson >> > wrote:
>>> On Jun 2, 2016, at 6:51 PM, John McCall via swift-evolution 
>>> > wrote:
>>> 
> On Jun 2, 2016, at 4:33 PM, Xiaodi Wu  > wrote:
> The IntegerLiteral type idea might be worth exploring. It does seem to 
> provide some additional consistency. For example, wasn't it clarified on 
> this list just recently that literals don't have a type and adopt one 
> based on context? It'd be nice to point out that 42 is an IntegerLiteral 
> when explaining that it's not an Int.
 
 I think that's a very promising way of thinking about literals.  Writing a 
 literal creates a notional value whose type is the informal, 
 infinite-precise type of all integer/FP/collection/etc. literals, which 
 (1) can be implicitly converted to any type that implements the 
 appropriate protocol and (2) in fact *must* be converted to some such type 
 (possibly the default type for that literal) in order for the code to be 
 executable.  You can then think about this proposal as saying that an 
 explicit conversion from that informal type to a literal-convertible type 
 follows the same path as an implicit conversion would have.
>>> 
>>> It sounds like the reason you don't want to remove the label is because it 
>>> distinguishes the literal initializer and you don't want it called with a 
>>> variable accidentally right?  
>>> 
>>> What if we do something like this:
>>> 
>>> init(_ value: IntegerLiteralType, literal: IntegerLiteral = #literal)
>>> 
>>> The idea here is that the IntegerLiteral type and friends are special types 
>>> that have no members and cannot be used except by the literal convertible 
>>> protocols and their conformances.  There is nothing you can do with the 
>>> value at all.  
>>> 
>>> The trick is that by defaulting it to #literal we are indicating the 
>>> compiler synthesizes the logical value, as with #file, #line, etc.  The 
>>> compiler would refuse to synthesize this value when a literal is not used.  
>>> This means it is never selected when the user provides a variable to a 
>>> converting initializer.  If an independent initializer accepting a value of 
>>> the same type also exists that would be selected.  However, when a literal 
>>> *is* used and the type conforms to the relevant literal convertible 
>>> protocol the compiler always synthesized the value making it always the 
>>> most specific overload.
>>> 
>>> Of course no runtime value would actually exist.  This is just a logical 
>>> value marking the fact that a literal was used to call the initializer.  
>>> 
>>> This approach solves the same problem while retaining semantic consistency 
>>> with the language (no label elision or short circuit of overload 
>>> resolution).  The magic is arguably a lot more restrained - types for which 
>>> values can only be supplied by the compiler.  We could artificially 
>>> restrict usage of these types if we wanted to, but we wouldn't have to.  
>>> Nothing could be accomplished by using the types anywhere else so nobody do 
>>> so and it wouldn't be actively harmful to allow them to be used anywhere 
>>> other types can be used.  Only the ability to create values of the type 
>>> needs to be restricted and we can already write types like that by marking 
>>> the initializers private.
>>> 
>>> Any thoughts on this approach?
>> 
>> This is still a special-case type-checking rule, which means that it's still 
>> basically my proposal except, instead of just rewriting the call to use a 
>> labeled literal initializer, it rewrites the call to use a magic initializer 
>> which cannot be used by users because it requires arguments that users 
>> cannot create.  I just don't understand the motivation here.  It's not a 
>> simpler language model to use, explain, or implement; it purports to be 
>> conceptually simpler and less magical while actually inventing two magic new 
>> language concepts (IntegerLiteral and #literal) on top of the same special 
>> cases.
> 
> I understand that this is still a special case and also that the 
> implementation is pretty much identical.  But I think the way it is presented 
> to users is important. 
> 
>  The motivation is to come up with a design that lets us implement your 
> proposal without magically eliding a parameter label.  There is no other case 
> in Swift where you can directly call any function (initializer or otherwise) 
> without including labels for all parameters that have external labels.

Don't think of it as omitting a parameter label.  Constructing a value from a 
literal is a 

Re: [swift-evolution] Proposal: 'T(literal)' should construct T using the appropriate literal protocol if possible

2016-06-03 Thread Xiaodi Wu via swift-evolution
On Fri, Jun 3, 2016 at 2:41 PM, Matthew Johnson 
wrote:

>
> On Jun 3, 2016, at 1:36 PM, John McCall  wrote:
>
> On Jun 2, 2016, at 6:48 PM, Matthew Johnson 
> wrote:
> On Jun 2, 2016, at 6:51 PM, John McCall via swift-evolution <
> swift-evolution@swift.org> wrote:
>
> On Jun 2, 2016, at 4:33 PM, Xiaodi Wu  wrote:
> The IntegerLiteral type idea might be worth exploring. It does seem to
> provide some additional consistency. For example, wasn't it clarified on
> this list just recently that literals don't have a type and adopt one based
> on context? It'd be nice to point out that 42 is an IntegerLiteral when
> explaining that it's not an Int.
>
>
> I think that's a very promising way of thinking about literals.  Writing a
> literal creates a notional value whose type is the informal,
> infinite-precise type of all integer/FP/collection/etc. literals, which (1)
> can be implicitly converted to any type that implements the appropriate
> protocol and (2) in fact *must* be converted to some such type (possibly
> the default type for that literal) in order for the code to be executable.
> You can then think about this proposal as saying that an explicit
> conversion from that informal type to a literal-convertible type follows
> the same path as an implicit conversion would have.
>
>
> It sounds like the reason you don't want to remove the label is because it
> distinguishes the literal initializer and you don't want it called with a
> variable accidentally right?
>
> What if we do something like this:
>
> init(_ value: IntegerLiteralType, literal: IntegerLiteral = #literal)
>
> The idea here is that the IntegerLiteral type and friends are special
> types that have no members and cannot be used except by the literal
> convertible protocols and their conformances.  There is nothing you can do
> with the value at all.
>
> The trick is that by defaulting it to #literal we are indicating the
> compiler synthesizes the logical value, as with #file, #line, etc.  The
> compiler would refuse to synthesize this value when a literal is not used.
> This means it is never selected when the user provides a variable to a
> converting initializer.  If an independent initializer accepting a value of
> the same type also exists that would be selected.  However, when a literal
> *is* used and the type conforms to the relevant literal convertible
> protocol the compiler always synthesized the value making it always the
> most specific overload.
>
> Of course no runtime value would actually exist.  This is just a logical
> value marking the fact that a literal was used to call the initializer.
>
> This approach solves the same problem while retaining semantic consistency
> with the language (no label elision or short circuit of overload
> resolution).  The magic is arguably a lot more restrained - types for which
> values can only be supplied by the compiler.  We could artificially
> restrict usage of these types if we wanted to, but we wouldn't have to.
> Nothing could be accomplished by using the types anywhere else so nobody do
> so and it wouldn't be actively harmful to allow them to be used anywhere
> other types can be used.  Only the ability to create values of the type
> needs to be restricted and we can already write types like that by marking
> the initializers private.
>
> Any thoughts on this approach?
>
>
> This is still a special-case type-checking rule, which means that it's
> still basically my proposal except, instead of just rewriting the call to
> use a labeled literal initializer, it rewrites the call to use a magic
> initializer which cannot be used by users because it requires arguments
> that users cannot create.  I just don't understand the motivation here.
> It's not a simpler language model to use, explain, or implement; it
> purports to be conceptually simpler and less magical while actually
> inventing two magic new language concepts (IntegerLiteral and #literal) on
> top of the same special cases.
>
>
> I understand that this is still a special case and also that the
> implementation is pretty much identical.  But I think the way it is
> presented to users is important.
>
>  The motivation is to come up with a design that lets us implement your
> proposal without magically eliding a parameter label.  There is no other
> case in Swift where you can directly call any function (initializer or
> otherwise) without including labels for all parameters that have external
> labels.  Creating a special case to allow that here is inconsistent.  Why
> wouldn’t look for a way to do this that treats the signature consistently
> with the rest of the language and is more in line with how we handle other
> compiler magic (i.e. #file, #line, etc)?
>
> I am not the only one who feels that way.  Quoting Brent:
>
> "But if you're going to call `init(integerLiteral:)` like it's `init(_:)`,
> I don't think that's a good idea. 

Re: [swift-evolution] Proposal: 'T(literal)' should construct T using the appropriate literal protocol if possible

2016-06-03 Thread Matthew Johnson via swift-evolution

> On Jun 3, 2016, at 1:36 PM, John McCall  wrote:
> 
>> On Jun 2, 2016, at 6:48 PM, Matthew Johnson > > wrote:
>> On Jun 2, 2016, at 6:51 PM, John McCall via swift-evolution 
>> > wrote:
>> 
 On Jun 2, 2016, at 4:33 PM, Xiaodi Wu > wrote:
 The IntegerLiteral type idea might be worth exploring. It does seem to 
 provide some additional consistency. For example, wasn't it clarified on 
 this list just recently that literals don't have a type and adopt one 
 based on context? It'd be nice to point out that 42 is an IntegerLiteral 
 when explaining that it's not an Int.
>>> 
>>> I think that's a very promising way of thinking about literals.  Writing a 
>>> literal creates a notional value whose type is the informal, 
>>> infinite-precise type of all integer/FP/collection/etc. literals, which (1) 
>>> can be implicitly converted to any type that implements the appropriate 
>>> protocol and (2) in fact *must* be converted to some such type (possibly 
>>> the default type for that literal) in order for the code to be executable.  
>>> You can then think about this proposal as saying that an explicit 
>>> conversion from that informal type to a literal-convertible type follows 
>>> the same path as an implicit conversion would have.
>> 
>> It sounds like the reason you don't want to remove the label is because it 
>> distinguishes the literal initializer and you don't want it called with a 
>> variable accidentally right?  
>> 
>> What if we do something like this:
>> 
>> init(_ value: IntegerLiteralType, literal: IntegerLiteral = #literal)
>> 
>> The idea here is that the IntegerLiteral type and friends are special types 
>> that have no members and cannot be used except by the literal convertible 
>> protocols and their conformances.  There is nothing you can do with the 
>> value at all.  
>> 
>> The trick is that by defaulting it to #literal we are indicating the 
>> compiler synthesizes the logical value, as with #file, #line, etc.  The 
>> compiler would refuse to synthesize this value when a literal is not used.  
>> This means it is never selected when the user provides a variable to a 
>> converting initializer.  If an independent initializer accepting a value of 
>> the same type also exists that would be selected.  However, when a literal 
>> *is* used and the type conforms to the relevant literal convertible protocol 
>> the compiler always synthesized the value making it always the most specific 
>> overload.
>> 
>> Of course no runtime value would actually exist.  This is just a logical 
>> value marking the fact that a literal was used to call the initializer.  
>> 
>> This approach solves the same problem while retaining semantic consistency 
>> with the language (no label elision or short circuit of overload 
>> resolution).  The magic is arguably a lot more restrained - types for which 
>> values can only be supplied by the compiler.  We could artificially restrict 
>> usage of these types if we wanted to, but we wouldn't have to.  Nothing 
>> could be accomplished by using the types anywhere else so nobody do so and 
>> it wouldn't be actively harmful to allow them to be used anywhere other 
>> types can be used.  Only the ability to create values of the type needs to 
>> be restricted and we can already write types like that by marking the 
>> initializers private.
>> 
>> Any thoughts on this approach?
> 
> This is still a special-case type-checking rule, which means that it's still 
> basically my proposal except, instead of just rewriting the call to use a 
> labeled literal initializer, it rewrites the call to use a magic initializer 
> which cannot be used by users because it requires arguments that users cannot 
> create.  I just don't understand the motivation here.  It's not a simpler 
> language model to use, explain, or implement; it purports to be conceptually 
> simpler and less magical while actually inventing two magic new language 
> concepts (IntegerLiteral and #literal) on top of the same special cases.

I understand that this is still a special case and also that the implementation 
is pretty much identical.  But I think the way it is presented to users is 
important. 

 The motivation is to come up with a design that lets us implement your 
proposal without magically eliding a parameter label.  There is no other case 
in Swift where you can directly call any function (initializer or otherwise) 
without including labels for all parameters that have external labels.  
Creating a special case to allow that here is inconsistent.  Why wouldn’t look 
for a way to do this that treats the signature consistently with the rest of 
the language and is more in line with how we handle other compiler magic (i.e. 
#file, #line, etc)?

I am not the only one who feels that way. 

Re: [swift-evolution] Proposal: 'T(literal)' should construct T using the appropriate literal protocol if possible

2016-06-03 Thread John McCall via swift-evolution
> On Jun 2, 2016, at 10:31 PM, L. Mihalkovic  
> wrote:
> On Jun 2, 2016, at 6:08 PM, John McCall via swift-evolution 
> > 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.
> 
> Looking transversally at all literal protocols as this proposes to operates 
> reminds me that the knowledge that a protocol has the right semantic is based 
> on a convention, rather than on conformance. Would it be conceibable to look 
> into something like the following, that all others would specialize.
> 
> protocol LiteralConvertible {}
> 
> This might offer a stronger identification than the name. It might also be 
> interesting to define an associated type, but that would exclude 
> NilLiteralConvertible.
> 
> Note: as compiler expert, I would appreciate your thinking on the notion of 
> formally expressing what might otherwise be a known strong semantic 
> relationship. Is there any incentive to pursue, known disavantages, ...

I don't know what you're saying here.  Literal types already do explicitly 
conform to a protocol that's specific to the literal; it's not just convention. 
 There's nothing linking those protocols because there's no useful operation in 
common: there is no useful generic code that you can write that works for an 
arbitrary type that allows some unknown kind of literal.  We intentionally do 
not add protocols that do not serve some useful purpose in generic programming.

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


Re: [swift-evolution] Proposal: 'T(literal)' should construct T using the appropriate literal protocol if possible

2016-06-03 Thread John McCall via swift-evolution
> On Jun 2, 2016, at 6:48 PM, Matthew Johnson  wrote:
> On Jun 2, 2016, at 6:51 PM, John McCall via swift-evolution 
> > wrote:
> 
>>> On Jun 2, 2016, at 4:33 PM, Xiaodi Wu >> > wrote:
>>> The IntegerLiteral type idea might be worth exploring. It does seem to 
>>> provide some additional consistency. For example, wasn't it clarified on 
>>> this list just recently that literals don't have a type and adopt one based 
>>> on context? It'd be nice to point out that 42 is an IntegerLiteral when 
>>> explaining that it's not an Int.
>> 
>> I think that's a very promising way of thinking about literals.  Writing a 
>> literal creates a notional value whose type is the informal, 
>> infinite-precise type of all integer/FP/collection/etc. literals, which (1) 
>> can be implicitly converted to any type that implements the appropriate 
>> protocol and (2) in fact *must* be converted to some such type (possibly the 
>> default type for that literal) in order for the code to be executable.  You 
>> can then think about this proposal as saying that an explicit conversion 
>> from that informal type to a literal-convertible type follows the same path 
>> as an implicit conversion would have.
> 
> It sounds like the reason you don't want to remove the label is because it 
> distinguishes the literal initializer and you don't want it called with a 
> variable accidentally right?  
> 
> What if we do something like this:
> 
> init(_ value: IntegerLiteralType, literal: IntegerLiteral = #literal)
> 
> The idea here is that the IntegerLiteral type and friends are special types 
> that have no members and cannot be used except by the literal convertible 
> protocols and their conformances.  There is nothing you can do with the value 
> at all.  
> 
> The trick is that by defaulting it to #literal we are indicating the compiler 
> synthesizes the logical value, as with #file, #line, etc.  The compiler would 
> refuse to synthesize this value when a literal is not used.  This means it is 
> never selected when the user provides a variable to a converting initializer. 
>  If an independent initializer accepting a value of the same type also exists 
> that would be selected.  However, when a literal *is* used and the type 
> conforms to the relevant literal convertible protocol the compiler always 
> synthesized the value making it always the most specific overload.
> 
> Of course no runtime value would actually exist.  This is just a logical 
> value marking the fact that a literal was used to call the initializer.  
> 
> This approach solves the same problem while retaining semantic consistency 
> with the language (no label elision or short circuit of overload resolution). 
>  The magic is arguably a lot more restrained - types for which values can 
> only be supplied by the compiler.  We could artificially restrict usage of 
> these types if we wanted to, but we wouldn't have to.  Nothing could be 
> accomplished by using the types anywhere else so nobody do so and it wouldn't 
> be actively harmful to allow them to be used anywhere other types can be 
> used.  Only the ability to create values of the type needs to be restricted 
> and we can already write types like that by marking the initializers private.
> 
> Any thoughts on this approach?

This is still a special-case type-checking rule, which means that it's still 
basically my proposal except, instead of just rewriting the call to use a 
labeled literal initializer, it rewrites the call to use a magic initializer 
which cannot be used by users because it requires arguments that users cannot 
create.  I just don't understand the motivation here.  It's not a simpler 
language model to use, explain, or implement; it purports to be conceptually 
simpler and less magical while actually inventing two magic new language 
concepts (IntegerLiteral and #literal) on top of the same special cases.

Literals are always going to involve some magic behind the scenes.  The 
non-trivial literals, for example, all actually traffic through some sort of 
builtin protocol (e.g. BuiltinIntegerLiteralConvertible) which cannot be 
implemented by users and whose construction necessarily involves a private API 
contract between the standard library and compiler that we reserve the right to 
change at will without bringing in swift-evolution.  All of the supposedly 
simple explanations eventually reach, "okay, but if Int isn't a special type, 
how does the literal turn into an Int in the first place", and that is just 
unanswerable, because it turns out that standard library types *are* actually 
special in the sense that they get to conform to 
BuiltinIntegerLiteralConvertible and nobody else does.

John.

> 
>> 
>> John.
>> 
>>> 
>>> On Thu, Jun 2, 2016 at 18:22 Brent Royal-Gordon via swift-evolution 
>>> 

Re: [swift-evolution] Proposal: 'T(literal)' should construct T using the appropriate literal protocol if possible

2016-06-03 Thread John McCall via swift-evolution
> On Jun 2, 2016, at 10:28 PM, Vladimir.S  wrote:
> > Like I said, the standard library and compiler conspire to make sure that 
> > easy cases like this are caught at compile time, but that would not help 
> > non-standard types that conform to IntegerLiteralConvertible.
> >
> > Also, even for standard types, the syntax only works statically if the 
> > literal fits in the range of Int, which may not be a superset of the 
> > desired type.  For example, UInt64(0x100) would not work on a 
> > 32-bit platform.  It is diagnosed statically, however.
> 
> I believe I understand the problem you described, but I really can't figure 
> out how this problem can produce a unexpected behavior and run-time errors, 
> as was stated in your initial message. So, this is why I was asking for any 
> code that can prove this. The example with UInt64(0x100) on 32bit 
> systems will raise error at _compilation_ time. Could someone provide any 
> code to illustrate the possible problems at run-time?

It's sufficient to do the same thing as the standard library, just without the 
@transparent tricks that enable static detection of the failure:

  struct WidgetCount : IntegerLiteralConvertible {
var value: UInt64
init(integerLiteral value: UInt64) {
  self.value = value
}
init(_ value: Int) {
  self.value = UInt64(value)
}
  }

  let count = WidgetCount(-1)

John.


> 
> For others, who not really understand the issue(probably I'm not the one, I 
> hope ;-) ) : If we'd have Int128 type, we can't create an instance of it in 
> this form:
> let x = Int128(92233720368547758070)
> (92233720368547758070 == Int.max * 10)
> as '92233720368547758070' literal will be treated always as of Int type.
> 
> In more general description, the difference between UIntN(xxx) and yyy as 
> UIntN is that xxx will be treated as Int(so it can't be greater than Int.max 
> for example) then this Int will be sent to UIntN(:Int) initializer and then 
> we have UIntN as a result of call to initializer; yyy will be treated as 
> UIntN literal just by its definition, no calling to any initializer, yyy can 
> be of any value allowed for UIntN.
> 
> But again, could someone help with examples when this can produce problems at 
> run-time?
> 
> On 03.06.2016 1:12, John McCall wrote:
>>> On Jun 2, 2016, at 2:36 PM, Vladimir.S  wrote:
>>> Well, I understand that it seems like there is some problem with UIntN() 
>>> initialization, but can't find any simple code that will demonstrate this..
>>> 
>>> All below works as expected:
>>> 
>>> var x1: Int32 = 0
>>> var x2 = Int32(0)
>>> 
>>> print(x1.dynamicType, x2.dynamicType) // Int32 Int32
>>> 
>>> // integer overflows when converted from 'Int' to 'UInt16'
>>> //var x = UInt16(100_000)
>>> //var x = UInt16(-10)
>>> 
>>> // negative integer cannot be converted to unsigned type 'UInt64'
>>> // var x = UInt64(-1)
>>> 
>>> So, what code will produce some unexpected behavior / error at runtime?
>> 
>> Like I said, the standard library and compiler conspire to make sure that 
>> easy cases like this are caught at compile time, but that would not help 
>> non-standard types that conform to IntegerLiteralConvertible.
>> 
>> Also, even for standard types, the syntax only works statically if the 
>> literal fits in the range of Int, which may not be a superset of the desired 
>> type.  For example, UInt64(0x100) would not work on a 32-bit 
>> platform.  It is diagnosed statically, however.
>> 
>> John.
>> 
>>> 
>>> On 03.06.2016 0:25, John McCall wrote:
> On Jun 2, 2016, at 1:56 PM, Vladimir.S  wrote:
>> 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.
> 
> Seems like I'm very slow today.. Could you present a couple of examples 
> where such initialization(like UInt16(7)) can produce some unexpected 
> behavior / error at runtime?
 
 UIntN has unlabeled initializers taking all of the standard integer types, 
 including itself.  The literal type will therefore get defaulted to Int.  
 The legal range of values for Int may not be a superset of the legal range 
 of values for UIntN.  If the literal is in the legal range for an Int but 
 not for the target type, this might trap at runtime.  Now, for a built-in 
 integer type like UInt16, we will recognize that the coercion always traps 
 and emit an error at compile-time, but this generally won't apply to other 
 types.
 
 John.
 
> 
> On 02.06.2016 19:08, John McCall via swift-evolution 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, 

Re: [swift-evolution] Proposal: 'T(literal)' should construct T using the appropriate literal protocol if possible

2016-06-02 Thread Vladimir.S via swift-evolution

> I was referring to the subtle distinction between creating an Int32 from a
> literal (the first one) and creating an Int from a literal and then
> coercing it to Int32 (the second one).

I understand the difference and just trying to find out if that 
behavior(Int32(x) vs x as Int32)  could really produce problems at run-time 
as was stated in initial message for this proposal.


On 03.06.2016 0:57, Tony Allevato wrote:

On Thu, Jun 2, 2016 at 2:38 PM Vladimir.S > wrote:

What is wrong with your examples?

var x1: Int32 = 0
var x2 = Int32(0)
print(x1.dynamicType, x2.dynamicType) // Int32 Int32


I was referring to the subtle distinction between creating an Int32 from a
literal (the first one) and creating an Int from a literal and then
coercing it to Int32 (the second one). So, I was pondering whether this was
the cause of some complex expressions I've had problems with in the past.
However, looking at the specific code, it looks like I had the *opposite*
problem.

This expression is evaluated quickly in Swift 2.2:

let value = Int64((0x1b << 0) | (0x28 << 7) | (0x79 << 14) | (0x42 << 21) |
(0x3b << 28) |
  (0x56 << 35) | (0x00 << 42) | (0x05 << 49) | (0x26 << 56) | (0x01 << 63))

This one errors out with "expression was too complex to be solved in
reasonable time":

let value: Int64 = (0x1b << 0) | (0x28 << 7) | (0x79 << 14) | (0x42 << 21)
| (0x3b << 28) |
  (0x56 << 35) | (0x00 << 42) | (0x05 << 49) | (0x26 << 56) | (0x01 << 63)




On 03.06.2016 0:17, Tony Allevato via swift-evolution wrote:
> +1. As someone who thought "var x: Int32 = 0" and "var x = Int32(0)" were
> equivalent, this is very good to know (and very good to fix).
>
> I'm starting to wonder now if some of the times I've hit "expression was
> too complex" errors with large 64-bit multi-term expressions with
literals
> were caused by coercions happening that I didn't realize.
>
>
> On Thu, Jun 2, 2016 at 9:31 AM John McCall via swift-evolution
> 
>>
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
> 

Re: [swift-evolution] Proposal: 'T(literal)' should construct T using the appropriate literal protocol if possible

2016-06-02 Thread L. Mihalkovic via swift-evolution

> On Jun 2, 2016, at 6:08 PM, John McCall via swift-evolution 
>  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.

Looking transversally at all literal protocols as this proposes to operates 
reminds me that the knowledge that a protocol has the right semantic is based 
on a convention, rather than on conformance. Would it be conceibable to look 
into something like the following, that all others would specialize.

protocol LiteralConvertible {}

This might offer a stronger identification than the name. It might also be 
interesting to define an associated type, but that would exclude 
NilLiteralConvertible.

Note: as compiler expert, I would appreciate your thinking on the notion of 
formally expressing what might otherwise be a known strong semantic 
relationship. Is there any incentive to pursue, known disavantages, ...


> 
> 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([]) 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


Re: [swift-evolution] Proposal: 'T(literal)' should construct T using the appropriate literal protocol if possible

2016-06-02 Thread Vladimir.S via swift-evolution
> Like I said, the standard library and compiler conspire to make sure 
that easy cases like this are caught at compile time, but that would not 
help non-standard types that conform to IntegerLiteralConvertible.

>
> Also, even for standard types, the syntax only works statically if the 
literal fits in the range of Int, which may not be a superset of the 
desired type.  For example, UInt64(0x100) would not work on a 
32-bit platform.  It is diagnosed statically, however.


I believe I understand the problem you described, but I really can't figure 
out how this problem can produce a unexpected behavior and run-time errors, 
as was stated in your initial message. So, this is why I was asking for any 
code that can prove this. The example with UInt64(0x100) on 32bit 
systems will raise error at _compilation_ time. Could someone provide any 
code to illustrate the possible problems at run-time? I understand that we 
need to fix this somehow in any case.


For others, who not really understand the issue(probably I'm not the one, I 
hope ;-) ) : If we'd have Int128 type, we can't create an instance of it in 
this form:

let x = Int128(92233720368547758070)
(92233720368547758070 == Int.max * 10)
as '92233720368547758070' literal will be treated always as of Int type.

In more general description, the difference between UIntN(xxx) and yyy as 
UIntN is that xxx will be treated as Int(so it can't be greater than 
Int.max for example) then this Int will be sent to UIntN(:Int) initializer 
and then we have UIntN as a result of call to initializer; yyy will be 
treated as UIntN literal just by its definition, no calling to any 
initializer, yyy can be of any value allowed for UIntN.


But again, could someone help with examples when this can produce problems 
at run-time?


On 03.06.2016 1:12, John McCall wrote:

On Jun 2, 2016, at 2:36 PM, Vladimir.S  wrote:
Well, I understand that it seems like there is some problem with UIntN() 
initialization, but can't find any simple code that will demonstrate this..

All below works as expected:

var x1: Int32 = 0
var x2 = Int32(0)

print(x1.dynamicType, x2.dynamicType) // Int32 Int32

// integer overflows when converted from 'Int' to 'UInt16'
//var x = UInt16(100_000)
//var x = UInt16(-10)

// negative integer cannot be converted to unsigned type 'UInt64'
// var x = UInt64(-1)

So, what code will produce some unexpected behavior / error at runtime?


Like I said, the standard library and compiler conspire to make sure that easy 
cases like this are caught at compile time, but that would not help 
non-standard types that conform to IntegerLiteralConvertible.

Also, even for standard types, the syntax only works statically if the literal 
fits in the range of Int, which may not be a superset of the desired type.  For 
example, UInt64(0x100) would not work on a 32-bit platform.  It is 
diagnosed statically, however.

John.



On 03.06.2016 0:25, John McCall wrote:

On Jun 2, 2016, at 1:56 PM, Vladimir.S  wrote:

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.


Seems like I'm very slow today.. Could you present a couple of examples where 
such initialization(like UInt16(7)) can produce some unexpected behavior / 
error at runtime?


UIntN has unlabeled initializers taking all of the standard integer types, 
including itself.  The literal type will therefore get defaulted to Int.  The 
legal range of values for Int may not be a superset of the legal range of 
values for UIntN.  If the literal is in the legal range for an Int but not for 
the target type, this might trap at runtime.  Now, for a built-in integer type 
like UInt16, we will recognize that the coercion always traps and emit an error 
at compile-time, but this generally won't apply to other types.

John.



On 02.06.2016 19:08, John McCall via swift-evolution 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 

Re: [swift-evolution] Proposal: 'T(literal)' should construct T using the appropriate literal protocol if possible

2016-06-02 Thread Matthew Johnson via swift-evolution


Sent from my iPad

>> On Jun 2, 2016, at 6:51 PM, John McCall via swift-evolution 
>>  wrote:
>> 
>> On Jun 2, 2016, at 4:33 PM, Xiaodi Wu  wrote:
>> The IntegerLiteral type idea might be worth exploring. It does seem to 
>> provide some additional consistency. For example, wasn't it clarified on 
>> this list just recently that literals don't have a type and adopt one based 
>> on context? It'd be nice to point out that 42 is an IntegerLiteral when 
>> explaining that it's not an Int.
> 
> I think that's a very promising way of thinking about literals.  Writing a 
> literal creates a notional value whose type is the informal, infinite-precise 
> type of all integer/FP/collection/etc. literals, which (1) can be implicitly 
> converted to any type that implements the appropriate protocol and (2) in 
> fact *must* be converted to some such type (possibly the default type for 
> that literal) in order for the code to be executable.  You can then think 
> about this proposal as saying that an explicit conversion from that informal 
> type to a literal-convertible type follows the same path as an implicit 
> conversion would have.

It sounds like the reason you don't want to remove the label is because it 
distinguishes the literal initializer and you don't want it called with a 
variable accidentally right?  

What if we do something like this:

init(_ value: IntegerLiteralType, literal: IntegerLiteral = #literal)

The idea here is that the IntegerLiteral type and friends are special types 
that have no members and cannot be used except by the literal convertible 
protocols and their conformances.  There is nothing you can do with the value 
at all.  

The trick is that by defaulting it to #literal we are indicating the compiler 
synthesizes the logical value, as with #file, #line, etc.  The compiler would 
refuse to synthesize this value when a literal is not used.  This means it is 
never selected when the user provides a variable to a converting initializer.  
If an independent initializer accepting a value of the same type also exists 
that would be selected.  However, when a literal *is* used and the type 
conforms to the relevant literal convertible protocol the compiler always 
synthesized the value making it always the most specific overload.

Of course no runtime value would actually exist.  This is just a logical value 
marking the fact that a literal was used to call the initializer.  

This approach solves the same problem while retaining semantic consistency with 
the language (no label elision or short circuit of overload resolution).  The 
magic is arguably a lot more restrained - types for which values can only be 
supplied by the compiler.  We could artificially restrict usage of these types 
if we wanted to, but we wouldn't have to.  Nothing could be accomplished by 
using the types anywhere else so nobody do so and it wouldn't be actively 
harmful to allow them to be used anywhere other types can be used.  Only the 
ability to create values of the type needs to be restricted and we can already 
write types like that by marking the initializers private.

Any thoughts on this approach?

> 
> John.
> 
>> 
>>> On Thu, Jun 2, 2016 at 18:22 Brent Royal-Gordon via swift-evolution 
>>>  wrote:
>>> > So, you think that this syntax is enticing to new developers who 
>>> > naturally think that the feature works the way that I'm proposing it 
>>> > should work, and you think that the right solution is to make the syntax 
>>> > illegal so that you can more conveniently tell them it doesn't work that 
>>> > way? :)
>>> 
>>> I think the difference between a cast (which merely reinterprets a value as 
>>> a compatible type) and a fullwidth conversion (which creates a similar 
>>> instance of an incompatible type) is very important to understanding how to 
>>> write Swift, and we shouldn't muddy the waters by creating a magic syntax.
>>> 
>>> > You can still tell them that it's a struct and you're calling an 
>>> > initializer on it; it's just that the initializer chosen is the special 
>>> > literal initializer because the argument is a literal.
>>> 
>>> If you're planning to change `IntegerLiteralConvertible` and friends to 
>>> require a fullwidth conversion initializer like `init(_ value: 
>>> IntegerLiteralType)`, then this is simply an overload resolution rule. In 
>>> that case, I think your proposal is fine.
>>> 
>>> But if you're going to call `init(integerLiteral:)` like it's `init(_:)`, I 
>>> don't think that's a good idea. Parameter labels are supposed to be 
>>> significant; we don't want to lose that.
>>> 
>>> --
>>> Brent Royal-Gordon
>>> Architechies
>>> 
>>> ___
>>> swift-evolution mailing list
>>> swift-evolution@swift.org
>>> https://lists.swift.org/mailman/listinfo/swift-evolution
> 
> ___
> swift-evolution mailing list
> 

Re: [swift-evolution] Proposal: 'T(literal)' should construct T using the appropriate literal protocol if possible

2016-06-02 Thread John McCall via swift-evolution
> On Jun 2, 2016, at 4:33 PM, Xiaodi Wu  wrote:
> The IntegerLiteral type idea might be worth exploring. It does seem to 
> provide some additional consistency. For example, wasn't it clarified on this 
> list just recently that literals don't have a type and adopt one based on 
> context? It'd be nice to point out that 42 is an IntegerLiteral when 
> explaining that it's not an Int.

I think that's a very promising way of thinking about literals.  Writing a 
literal creates a notional value whose type is the informal, infinite-precise 
type of all integer/FP/collection/etc. literals, which (1) can be implicitly 
converted to any type that implements the appropriate protocol and (2) in fact 
*must* be converted to some such type (possibly the default type for that 
literal) in order for the code to be executable.  You can then think about this 
proposal as saying that an explicit conversion from that informal type to a 
literal-convertible type follows the same path as an implicit conversion would 
have.

John.

> 
> On Thu, Jun 2, 2016 at 18:22 Brent Royal-Gordon via swift-evolution 
> > wrote:
> > So, you think that this syntax is enticing to new developers who naturally 
> > think that the feature works the way that I'm proposing it should work, and 
> > you think that the right solution is to make the syntax illegal so that you 
> > can more conveniently tell them it doesn't work that way? :)
> 
> I think the difference between a cast (which merely reinterprets a value as a 
> compatible type) and a fullwidth conversion (which creates a similar instance 
> of an incompatible type) is very important to understanding how to write 
> Swift, and we shouldn't muddy the waters by creating a magic syntax.
> 
> > You can still tell them that it's a struct and you're calling an 
> > initializer on it; it's just that the initializer chosen is the special 
> > literal initializer because the argument is a literal.
> 
> If you're planning to change `IntegerLiteralConvertible` and friends to 
> require a fullwidth conversion initializer like `init(_ value: 
> IntegerLiteralType)`, then this is simply an overload resolution rule. In 
> that case, I think your proposal is fine.
> 
> But if you're going to call `init(integerLiteral:)` like it's `init(_:)`, I 
> don't think that's a good idea. Parameter labels are supposed to be 
> significant; we don't want to lose that.
> 
> --
> Brent Royal-Gordon
> Architechies
> 
> ___
> 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


Re: [swift-evolution] Proposal: 'T(literal)' should construct T using the appropriate literal protocol if possible

2016-06-02 Thread Xiaodi Wu via swift-evolution
The IntegerLiteral type idea might be worth exploring. It does seem to
provide some additional consistency. For example, wasn't it clarified on
this list just recently that literals don't have a type and adopt one based
on context? It'd be nice to point out that 42 is an IntegerLiteral when
explaining that it's not an Int.

On Thu, Jun 2, 2016 at 18:22 Brent Royal-Gordon via swift-evolution <
swift-evolution@swift.org> wrote:

> > So, you think that this syntax is enticing to new developers who
> naturally think that the feature works the way that I'm proposing it should
> work, and you think that the right solution is to make the syntax illegal
> so that you can more conveniently tell them it doesn't work that way? :)
>
> I think the difference between a cast (which merely reinterprets a value
> as a compatible type) and a fullwidth conversion (which creates a similar
> instance of an incompatible type) is very important to understanding how to
> write Swift, and we shouldn't muddy the waters by creating a magic syntax.
>
> > You can still tell them that it's a struct and you're calling an
> initializer on it; it's just that the initializer chosen is the special
> literal initializer because the argument is a literal.
>
> If you're planning to change `IntegerLiteralConvertible` and friends to
> require a fullwidth conversion initializer like `init(_ value:
> IntegerLiteralType)`, then this is simply an overload resolution rule. In
> that case, I think your proposal is fine.
>
> But if you're going to call `init(integerLiteral:)` like it's `init(_:)`,
> I don't think that's a good idea. Parameter labels are supposed to be
> significant; we don't want to lose that.
>
> --
> Brent Royal-Gordon
> Architechies
>
> ___
> 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


Re: [swift-evolution] Proposal: 'T(literal)' should construct T using the appropriate literal protocol if possible

2016-06-02 Thread T.J. Usiyan via swift-evolution
+1
It has nagged at me that this can happen even though I understood *why* it
happens.

On Thu, Jun 2, 2016 at 6:22 PM, John McCall via swift-evolution <
swift-evolution@swift.org> wrote:

> > On Jun 2, 2016, at 2:43 PM, Brent Royal-Gordon 
> wrote:
> >> 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.
> >
> > I've seen developers do this; in one memorable case, it resulted in
> Swift taking a ridiculously long time to typecheck an expression, since the
> seemingly pinned-down types of the literals had actually become *more*
> ambiguous, not less.
>
> Yes, this would also tend to improve compile times, since currently we end
> up generating a massively-ambiguous constraint system which must be
> resolved by type defaulting.  That's not really why I'm proposing this,
> though.
>
> > However, it's not difficult to teach developers to use `as`. Usually
> what's happening is that their mental model of the language is wrong: they
> think of `UInt16(foo)` as a cast to a primitive type, and are surprised to
> learn that it's actually an initializer on a struct and they're
> initializing an instance. Learning this helps them understand how the
> language works, what the difference is between initializers and `as`, and
> how they can write the same things they see in the standard library types.
>
> So, you think that this syntax is enticing to new developers who naturally
> think that the feature works the way that I'm proposing it should work, and
> you think that the right solution is to make the syntax illegal so that you
> can more conveniently tell them it doesn't work that way? :)
>
> You can still tell them that it's a struct and you're calling an
> initializer on it; it's just that the initializer chosen is the special
> literal initializer because the argument is a literal.
>
> John.
>
>
>
> >
> > I think *actually* turning this into magic would be counterproductive.
> The better solution is to make the compiler replace me in that story, by
> having it emit a warning with a fix-it. It keeps initializer calls meaning
> exactly what they say. (And it doesn't require an evolution proposal to do,
> since you can add a warning with a mere bug.)
> >
> >   UInt16(42)
> >   ^~ ^~
> >   Use of initializer with integer literal does not cast '42' to
> 'UInt16'
> >   Fix-It: Replace with '42 as UInt16'
> >
> > --
> > Brent Royal-Gordon
> > Architechies
> >
>
> ___
> 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


Re: [swift-evolution] Proposal: 'T(literal)' should construct T using the appropriate literal protocol if possible

2016-06-02 Thread Brent Royal-Gordon via swift-evolution
> So, you think that this syntax is enticing to new developers who naturally 
> think that the feature works the way that I'm proposing it should work, and 
> you think that the right solution is to make the syntax illegal so that you 
> can more conveniently tell them it doesn't work that way? :)

I think the difference between a cast (which merely reinterprets a value as a 
compatible type) and a fullwidth conversion (which creates a similar instance 
of an incompatible type) is very important to understanding how to write Swift, 
and we shouldn't muddy the waters by creating a magic syntax.

> You can still tell them that it's a struct and you're calling an initializer 
> on it; it's just that the initializer chosen is the special literal 
> initializer because the argument is a literal.

If you're planning to change `IntegerLiteralConvertible` and friends to require 
a fullwidth conversion initializer like `init(_ value: IntegerLiteralType)`, 
then this is simply an overload resolution rule. In that case, I think your 
proposal is fine.

But if you're going to call `init(integerLiteral:)` like it's `init(_:)`, I 
don't think that's a good idea. Parameter labels are supposed to be 
significant; we don't want to lose that.

-- 
Brent Royal-Gordon
Architechies

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


Re: [swift-evolution] Proposal: 'T(literal)' should construct T using the appropriate literal protocol if possible

2016-06-02 Thread John McCall via swift-evolution
> On Jun 2, 2016, at 2:43 PM, Brent Royal-Gordon  wrote:
>> 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.
> 
> I've seen developers do this; in one memorable case, it resulted in Swift 
> taking a ridiculously long time to typecheck an expression, since the 
> seemingly pinned-down types of the literals had actually become *more* 
> ambiguous, not less.

Yes, this would also tend to improve compile times, since currently we end up 
generating a massively-ambiguous constraint system which must be resolved by 
type defaulting.  That's not really why I'm proposing this, though.

> However, it's not difficult to teach developers to use `as`. Usually what's 
> happening is that their mental model of the language is wrong: they think of 
> `UInt16(foo)` as a cast to a primitive type, and are surprised to learn that 
> it's actually an initializer on a struct and they're initializing an 
> instance. Learning this helps them understand how the language works, what 
> the difference is between initializers and `as`, and how they can write the 
> same things they see in the standard library types.

So, you think that this syntax is enticing to new developers who naturally 
think that the feature works the way that I'm proposing it should work, and you 
think that the right solution is to make the syntax illegal so that you can 
more conveniently tell them it doesn't work that way? :)

You can still tell them that it's a struct and you're calling an initializer on 
it; it's just that the initializer chosen is the special literal initializer 
because the argument is a literal.

John.



> 
> I think *actually* turning this into magic would be counterproductive. The 
> better solution is to make the compiler replace me in that story, by having 
> it emit a warning with a fix-it. It keeps initializer calls meaning exactly 
> what they say. (And it doesn't require an evolution proposal to do, since you 
> can add a warning with a mere bug.)
> 
>   UInt16(42)
>   ^~ ^~
>   Use of initializer with integer literal does not cast '42' to 'UInt16'
>   Fix-It: Replace with '42 as UInt16'
> 
> -- 
> Brent Royal-Gordon
> Architechies
> 

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


Re: [swift-evolution] Proposal: 'T(literal)' should construct T using the appropriate literal protocol if possible

2016-06-02 Thread John McCall via swift-evolution
> On Jun 2, 2016, at 2:36 PM, Vladimir.S  wrote:
> Well, I understand that it seems like there is some problem with UIntN() 
> initialization, but can't find any simple code that will demonstrate this..
> 
> All below works as expected:
> 
> var x1: Int32 = 0
> var x2 = Int32(0)
> 
> print(x1.dynamicType, x2.dynamicType) // Int32 Int32
> 
> // integer overflows when converted from 'Int' to 'UInt16'
> //var x = UInt16(100_000)
> //var x = UInt16(-10)
> 
> // negative integer cannot be converted to unsigned type 'UInt64'
> // var x = UInt64(-1)
> 
> So, what code will produce some unexpected behavior / error at runtime?

Like I said, the standard library and compiler conspire to make sure that easy 
cases like this are caught at compile time, but that would not help 
non-standard types that conform to IntegerLiteralConvertible.

Also, even for standard types, the syntax only works statically if the literal 
fits in the range of Int, which may not be a superset of the desired type.  For 
example, UInt64(0x100) would not work on a 32-bit platform.  It is 
diagnosed statically, however.

John.

> 
> On 03.06.2016 0:25, John McCall wrote:
>>> On Jun 2, 2016, at 1:56 PM, Vladimir.S  wrote:
 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.
>>> 
>>> Seems like I'm very slow today.. Could you present a couple of examples 
>>> where such initialization(like UInt16(7)) can produce some unexpected 
>>> behavior / error at runtime?
>> 
>> UIntN has unlabeled initializers taking all of the standard integer types, 
>> including itself.  The literal type will therefore get defaulted to Int.  
>> The legal range of values for Int may not be a superset of the legal range 
>> of values for UIntN.  If the literal is in the legal range for an Int but 
>> not for the target type, this might trap at runtime.  Now, for a built-in 
>> integer type like UInt16, we will recognize that the coercion always traps 
>> and emit an error at compile-time, but this generally won't apply to other 
>> types.
>> 
>> John.
>> 
>>> 
>>> On 02.06.2016 19:08, John McCall via swift-evolution 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
 

Re: [swift-evolution] Proposal: 'T(literal)' should construct T using the appropriate literal protocol if possible

2016-06-02 Thread Tony Allevato via swift-evolution
On Thu, Jun 2, 2016 at 2:38 PM Vladimir.S  wrote:

> What is wrong with your examples?
>
> var x1: Int32 = 0
> var x2 = Int32(0)
> print(x1.dynamicType, x2.dynamicType) // Int32 Int32
>

I was referring to the subtle distinction between creating an Int32 from a
literal (the first one) and creating an Int from a literal and then
coercing it to Int32 (the second one). So, I was pondering whether this was
the cause of some complex expressions I've had problems with in the past.
However, looking at the specific code, it looks like I had the *opposite*
problem.

This expression is evaluated quickly in Swift 2.2:

let value = Int64((0x1b << 0) | (0x28 << 7) | (0x79 << 14) | (0x42 << 21) |
(0x3b << 28) |
  (0x56 << 35) | (0x00 << 42) | (0x05 << 49) | (0x26 << 56) | (0x01 <<
63))

This one errors out with "expression was too complex to be solved in
reasonable time":

let value: Int64 = (0x1b << 0) | (0x28 << 7) | (0x79 << 14) | (0x42 << 21)
| (0x3b << 28) |
  (0x56 << 35) | (0x00 << 42) | (0x05 << 49) | (0x26 << 56) | (0x01 <<
63)



>
> On 03.06.2016 0:17, Tony Allevato via swift-evolution wrote:
> > +1. As someone who thought "var x: Int32 = 0" and "var x = Int32(0)" were
> > equivalent, this is very good to know (and very good to fix).
> >
> > I'm starting to wonder now if some of the times I've hit "expression was
> > too complex" errors with large 64-bit multi-term expressions with
> literals
> > were caused by coercions happening that I didn't realize.
> >
> >
> > On Thu, Jun 2, 2016 at 9:31 AM John McCall via swift-evolution
> > > 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([]) 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.
> > 

Re: [swift-evolution] Proposal: 'T(literal)' should construct T using the appropriate literal protocol if possible

2016-06-02 Thread Xiaodi Wu via swift-evolution
See, I've made this mistake as well, and *not* because I thought it casts
the literal. I had always assumed that something like `UInt16(42)` would
initialize using the integer literal init, since it seems logical that
that's the most specific. The proposed change reflects my currently
erroneous mental model.
On Thu, Jun 2, 2016 at 16:42 Brent Royal-Gordon via swift-evolution <
swift-evolution@swift.org> wrote:

> > 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.
>
> I've seen developers do this; in one memorable case, it resulted in Swift
> taking a ridiculously long time to typecheck an expression, since the
> seemingly pinned-down types of the literals had actually become *more*
> ambiguous, not less.
>
> However, it's not difficult to teach developers to use `as`. Usually
> what's happening is that their mental model of the language is wrong: they
> think of `UInt16(foo)` as a cast to a primitive type, and are surprised to
> learn that it's actually an initializer on a struct and they're
> initializing an instance. Learning this helps them understand how the
> language works, what the difference is between initializers and `as`, and
> how they can write the same things they see in the standard library types.
>
> I think *actually* turning this into magic would be counterproductive. The
> better solution is to make the compiler replace me in that story, by having
> it emit a warning with a fix-it. It keeps initializer calls meaning exactly
> what they say. (And it doesn't require an evolution proposal to do, since
> you can add a warning with a mere bug.)
>
> UInt16(42)
> ^~ ^~
> Use of initializer with integer literal does not cast '42' to
> 'UInt16'
> Fix-It: Replace with '42 as UInt16'
>
> --
> Brent Royal-Gordon
> Architechies
>
> ___
> 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


Re: [swift-evolution] Proposal: 'T(literal)' should construct T using the appropriate literal protocol if possible

2016-06-02 Thread Brent Royal-Gordon via swift-evolution
> 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.

I've seen developers do this; in one memorable case, it resulted in Swift 
taking a ridiculously long time to typecheck an expression, since the seemingly 
pinned-down types of the literals had actually become *more* ambiguous, not 
less.

However, it's not difficult to teach developers to use `as`. Usually what's 
happening is that their mental model of the language is wrong: they think of 
`UInt16(foo)` as a cast to a primitive type, and are surprised to learn that 
it's actually an initializer on a struct and they're initializing an instance. 
Learning this helps them understand how the language works, what the difference 
is between initializers and `as`, and how they can write the same things they 
see in the standard library types.

I think *actually* turning this into magic would be counterproductive. The 
better solution is to make the compiler replace me in that story, by having it 
emit a warning with a fix-it. It keeps initializer calls meaning exactly what 
they say. (And it doesn't require an evolution proposal to do, since you can 
add a warning with a mere bug.)

UInt16(42)
^~ ^~
Use of initializer with integer literal does not cast '42' to 'UInt16'
Fix-It: Replace with '42 as UInt16'

-- 
Brent Royal-Gordon
Architechies

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


Re: [swift-evolution] Proposal: 'T(literal)' should construct T using the appropriate literal protocol if possible

2016-06-02 Thread Vladimir.S via swift-evolution

What is wrong with your examples?

var x1: Int32 = 0
var x2 = Int32(0)
print(x1.dynamicType, x2.dynamicType) // Int32 Int32


On 03.06.2016 0:17, Tony Allevato via swift-evolution wrote:

+1. As someone who thought "var x: Int32 = 0" and "var x = Int32(0)" were
equivalent, this is very good to know (and very good to fix).

I'm starting to wonder now if some of the times I've hit "expression was
too complex" errors with large 64-bit multi-term expressions with literals
were caused by coercions happening that I didn't realize.


On Thu, Jun 2, 2016 at 9:31 AM John McCall via swift-evolution
> 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([]) 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


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


Re: [swift-evolution] Proposal: 'T(literal)' should construct T using the appropriate literal protocol if possible

2016-06-02 Thread Vladimir.S via swift-evolution
Well, I understand that it seems like there is some problem with UIntN() 
initialization, but can't find any simple code that will demonstrate this..


All below works as expected:

var x1: Int32 = 0
var x2 = Int32(0)

print(x1.dynamicType, x2.dynamicType) // Int32 Int32

// integer overflows when converted from 'Int' to 'UInt16'
//var x = UInt16(100_000)
//var x = UInt16(-10)

// negative integer cannot be converted to unsigned type 'UInt64'
// var x = UInt64(-1)

So, what code will produce some unexpected behavior / error at runtime?

On 03.06.2016 0:25, John McCall wrote:

On Jun 2, 2016, at 1:56 PM, Vladimir.S  wrote:

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.


Seems like I'm very slow today.. Could you present a couple of examples where 
such initialization(like UInt16(7)) can produce some unexpected behavior / 
error at runtime?


UIntN has unlabeled initializers taking all of the standard integer types, 
including itself.  The literal type will therefore get defaulted to Int.  The 
legal range of values for Int may not be a superset of the legal range of 
values for UIntN.  If the literal is in the legal range for an Int but not for 
the target type, this might trap at runtime.  Now, for a built-in integer type 
like UInt16, we will recognize that the coercion always traps and emit an error 
at compile-time, but this generally won't apply to other types.

John.



On 02.06.2016 19:08, John McCall via swift-evolution 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([]) 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


Re: [swift-evolution] Proposal: 'T(literal)' should construct T using the appropriate literal protocol if possible

2016-06-02 Thread John McCall via swift-evolution
> On Jun 2, 2016, at 1:56 PM, Vladimir.S  wrote:
> > 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.
> 
> Seems like I'm very slow today.. Could you present a couple of examples where 
> such initialization(like UInt16(7)) can produce some unexpected behavior / 
> error at runtime?

UIntN has unlabeled initializers taking all of the standard integer types, 
including itself.  The literal type will therefore get defaulted to Int.  The 
legal range of values for Int may not be a superset of the legal range of 
values for UIntN.  If the literal is in the legal range for an Int but not for 
the target type, this might trap at runtime.  Now, for a built-in integer type 
like UInt16, we will recognize that the coercion always traps and emit an error 
at compile-time, but this generally won't apply to other types.

John.

> 
> On 02.06.2016 19:08, John McCall via swift-evolution 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([]) 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


Re: [swift-evolution] Proposal: 'T(literal)' should construct T using the appropriate literal protocol if possible

2016-06-02 Thread Tony Allevato via swift-evolution
+1. As someone who thought "var x: Int32 = 0" and "var x = Int32(0)" were
equivalent, this is very good to know (and very good to fix).

I'm starting to wonder now if some of the times I've hit "expression was
too complex" errors with large 64-bit multi-term expressions with literals
were caused by coercions happening that I didn't realize.


On Thu, Jun 2, 2016 at 9:31 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([]) 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


Re: [swift-evolution] Proposal: 'T(literal)' should construct T using the appropriate literal protocol if possible

2016-06-02 Thread Russ Bishop via swift-evolution

> On Jun 2, 2016, at 9:08 AM, John McCall via swift-evolution 
>  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.


+1 to the proposal; I’m embarrassed to admit I thought it worked this way 
already. 

Any type that wants more control shouldn’t be adopting the literal convertible 
protocols anyway.

Russ

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


Re: [swift-evolution] Proposal: 'T(literal)' should construct T using the appropriate literal protocol if possible

2016-06-02 Thread Vladimir.S via swift-evolution

> 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.

Seems like I'm very slow today.. Could you present a couple of examples 
where such initialization(like UInt16(7)) can produce some unexpected 
behavior / error at runtime?


On 02.06.2016 19:08, John McCall via swift-evolution 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([]) 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


Re: [swift-evolution] Proposal: 'T(literal)' should construct T using the appropriate literal protocol if possible

2016-06-02 Thread Matthew Johnson via swift-evolution


Sent from my iPad

> On Jun 2, 2016, at 3:41 PM, John McCall  wrote:
> 
>>> On Jun 2, 2016, at 12:10 PM, Matthew Johnson  wrote:
>>> On Jun 2, 2016, at 1:46 PM, Austin Zheng via swift-evolution 
>>>  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 
  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 

Re: [swift-evolution] Proposal: 'T(literal)' should construct T using the appropriate literal protocol if possible

2016-06-02 Thread Austin Zheng via swift-evolution
That makes sense. Thanks for sharing your reasoning.

On Thu, Jun 2, 2016 at 1:38 PM, John McCall  wrote:

> On Jun 2, 2016, at 11:55 AM, Austin Zheng  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 
> 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 

Re: [swift-evolution] Proposal: 'T(literal)' should construct T using the appropriate literal protocol if possible

2016-06-02 Thread John McCall via swift-evolution
> On Jun 2, 2016, at 12:10 PM, Matthew Johnson  wrote:
>> On Jun 2, 2016, at 1:46 PM, Austin Zheng via swift-evolution 
>> > 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.

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 
>> > 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([]) or the same with a typealias, but I 
>> think there's some benefit from having a simpler specification, both for the 
>> 

Re: [swift-evolution] Proposal: 'T(literal)' should construct T using the appropriate literal protocol if possible

2016-06-02 Thread John McCall via swift-evolution
> On Jun 2, 2016, at 11:55 AM, Austin Zheng  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  > 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 
> > 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 

Re: [swift-evolution] Proposal: 'T(literal)' should construct T using the appropriate literal protocol if possible

2016-06-02 Thread David Sweeris via swift-evolution

> On Jun 2, 2016, at 12:57 PM, John McCall  wrote:
> 
>> On Jun 2, 2016, at 10:49 AM, David Sweeris > > wrote:
>> I’m not entirely sure what an “expr-collection” is.
> 
> Collection literals, e.g. [x,y,z] and [a: x, b: y].
Thought so, but I wasn’t sure. Thanks for clarifying :-)

> 
>> 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.

Oh, I know. The crux of my concern is that while the difference between 
`UInt16(7)` and `7 as UInt16` is subtle, it’s not that subtle… the literal 
convertible syntax doesn’t even look that much like a call to init, so it 
shouldn’t be that surprising if explicitly calling the init function might send 
you down a different code path. OTOH, this proposal silently (and invisibly) 
rewrites an explicit call to`init(_: Int)` to `init(integerLiteral: 
IntegerLiteralType)`, which seems worse. Again, I don’t disagree that there’s a 
subtlety here, but at least with the current behavior, the unexpected behavior 
comes from not paying attention to syntax.

>> 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.

I can’t think of why anyone would either — all my *LiteralConvertible types 
just pass on the literal arguments to an init that takes an Int (or whatever) — 
but “a failure of imagination…”

I guess I’m just saying that with the way Swift treats literals, potential 
confusion is inevitable, and that it’s better to contain the subtleties to 
syntax which already involves some implicit behavior, rather than to start 
rewriting explicit code simply because we think the programmer doesn’t know 
what they’re doing.

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


Re: [swift-evolution] Proposal: 'T(literal)' should construct T using the appropriate literal protocol if possible

2016-06-02 Thread Matthew Johnson via swift-evolution

> On Jun 2, 2016, at 1:55 PM, Austin Zheng via swift-evolution 
>  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’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.

> 
> If this proposal isn't accepted, disallow using literal values as the 
> argument to one-unlabeled-argument constructors.

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.

For example, if I have:

`init(_ a: [String])`

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. 

FWIW, there are types in the standard library with overlapping initializers in 
this new model:

public init(_ value: UInt8)
public init(integerLiteral value: UInt8)

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.

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.

> 
> In either case we should disabuse users of the notion that A(literal) is an 
> initializer that behaves exactly the same as other initializers.
> 
> Austin
> 
> On Thu, Jun 2, 2016 at 11:46 AM, Austin Zheng  > 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 
> > 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 

Re: [swift-evolution] Proposal: 'T(literal)' should construct T using the appropriate literal protocol if possible

2016-06-02 Thread Austin Zheng via swift-evolution
On Thu, Jun 2, 2016 at 12:11 PM, Xiaodi Wu  wrote:

> +1 to the proposal. I can also see the argument for disallowing multiple
> ways of doing the same thing, though disallowing the use of `as` in this
> way might be introducing another special case.
>
>
The "as", "as?" and "as!" operators in Swift are already surprisingly
overloaded.  Joe Groff's proposal lists 9 (!!!) different things "as?" does
here:
https://github.com/apple/swift-evolution/blob/master/proposals/0083-remove-bridging-from-dynamic-casts.md
.

"as" is also overloaded in this sense. It performs bridging casts (soon to
go away?), upcasts that can never fail (e.g. subclass to superclass), and
defining the concrete type of a literal expression. It wouldn't be a big
loss for "as" to lose the last meaning.



> If the proposal is accepted, I'd also advocate for the suggestion in the
> initial proposal to apply the rule regardless of the number of parentheses,
> so that `A((B))` behaves the same way as `A(B)`.
>

+1. Yes please.


>
> On Thu, Jun 2, 2016 at 1:55 PM, Austin Zheng via swift-evolution <
> swift-evolution@swift.org> 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.
>>
>> If this proposal isn't accepted, disallow using literal values as the
>> argument to one-unlabeled-argument constructors.
>>
>> In either case we should disabuse users of the notion that A(literal) is
>> an initializer that behaves exactly the same as other initializers.
>>
>> Austin
>>
>> On Thu, Jun 2, 2016 at 11:46 AM, Austin Zheng 
>> 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 

Re: [swift-evolution] Proposal: 'T(literal)' should construct T using the appropriate literal protocol if possible

2016-06-02 Thread David Waite via swift-evolution
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 
>  wrote:
> 
>> On Jun 2, 2016, at 10:49 AM, David Sweeris > > 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 
>>> > 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([]) 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 
>>> 

Re: [swift-evolution] Proposal: 'T(literal)' should construct T using the appropriate literal protocol if possible

2016-06-02 Thread Xiaodi Wu via swift-evolution
+1 to the proposal. I can also see the argument for disallowing multiple
ways of doing the same thing, though disallowing the use of `as` in this
way might be introducing another special case.

If the proposal is accepted, I'd also advocate for the suggestion in the
initial proposal to apply the rule regardless of the number of parentheses,
so that `A((B))` behaves the same way as `A(B)`.

On Thu, Jun 2, 2016 at 1:55 PM, Austin Zheng via swift-evolution <
swift-evolution@swift.org> 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.
>
> If this proposal isn't accepted, disallow using literal values as the
> argument to one-unlabeled-argument constructors.
>
> In either case we should disabuse users of the notion that A(literal) is
> an initializer that behaves exactly the same as other initializers.
>
> Austin
>
> On Thu, Jun 2, 2016 at 11:46 AM, Austin Zheng 
> 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([]) 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.
>>>
>>> 

Re: [swift-evolution] Proposal: 'T(literal)' should construct T using the appropriate literal protocol if possible

2016-06-02 Thread Matthew Johnson via swift-evolution

> On Jun 2, 2016, at 1:46 PM, Austin Zheng via swift-evolution 
>  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.

> 
> 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 
> > 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([]) 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 
> 
> 
> 
> ___
> 

Re: [swift-evolution] Proposal: 'T(literal)' should construct T using the appropriate literal protocol if possible

2016-06-02 Thread Austin Zheng via swift-evolution
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.

If this proposal isn't accepted, disallow using literal values as the
argument to one-unlabeled-argument constructors.

In either case we should disabuse users of the notion that A(literal) is an
initializer that behaves exactly the same as other initializers.

Austin

On Thu, Jun 2, 2016 at 11:46 AM, Austin Zheng  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([]) 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


Re: [swift-evolution] Proposal: 'T(literal)' should construct T using the appropriate literal protocol if possible

2016-06-02 Thread Sean Heber via swift-evolution
+1

l8r
Sean


> On Jun 2, 2016, at 1:46 PM, Austin Zheng via swift-evolution 
>  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 
>  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([]) 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

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


Re: [swift-evolution] Proposal: 'T(literal)' should construct T using the appropriate literal protocol if possible

2016-06-02 Thread Austin Zheng via swift-evolution
+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([]) 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


Re: [swift-evolution] Proposal: 'T(literal)' should construct T using the appropriate literal protocol if possible

2016-06-02 Thread Matthew Johnson via swift-evolution
+1 to this.  It seems like a very straightforward thing to do.

Sent from my iPad

> On Jun 2, 2016, at 11:08 AM, John McCall via swift-evolution 
>  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([]) 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


Re: [swift-evolution] Proposal: 'T(literal)' should construct T using the appropriate literal protocol if possible

2016-06-02 Thread Christopher Kornher via swift-evolution
+1
 I have started using the ‘()’ syntax without even thinking about it. I never 
knew that it behaved in the way described. Using ‘()’ syntax will be natural 
for anyone with C++ experience.


> On Jun 2, 2016, at 10:08 AM, John McCall via swift-evolution 
>  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([]) 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


Re: [swift-evolution] Proposal: 'T(literal)' should construct T using the appropriate literal protocol if possible

2016-06-02 Thread John McCall via swift-evolution
> On Jun 2, 2016, at 10:49 AM, David Sweeris  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 
>> > 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([]) 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


Re: [swift-evolution] Proposal: 'T(literal)' should construct T using the appropriate literal protocol if possible

2016-06-02 Thread David Sweeris via swift-evolution
I’m not entirely sure what an “expr-collection” is. 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`? If so, that seems a 
potential source of much subtler problems.

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.

So… I’m tentatively -1

- Dave Sweeris

> On Jun 2, 2016, at 11:08 AM, John McCall via swift-evolution 
>  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([]) 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


[swift-evolution] Proposal: 'T(literal)' should construct T using the appropriate literal protocol if possible

2016-06-02 Thread John McCall via swift-evolution
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([]) 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