> On Nov 27, 2017, at 1:43 AM, David Hart <da...@hartbit.com> wrote:
> On 27 Nov 2017, at 07:32, John McCall <rjmcc...@apple.com 
> <mailto:rjmcc...@apple.com>> wrote:
> 
>> 
>>> On Nov 22, 2017, at 2:01 AM, David Hart via swift-evolution 
>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>>> 
>>> 
>>> 
>>>> On 22 Nov 2017, at 07:48, David Hart via swift-evolution 
>>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>>>> 
>>>> 
>>>> 
>>>> On 22 Nov 2017, at 07:41, Douglas Gregor via swift-evolution 
>>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>>>> 
>>>>> 
>>>>> 
>>>>>> On Nov 21, 2017, at 10:37 PM, Chris Lattner <clatt...@nondot.org 
>>>>>> <mailto:clatt...@nondot.org>> wrote:
>>>>>> 
>>>>>> On Nov 21, 2017, at 9:25 PM, Douglas Gregor <dgre...@apple.com 
>>>>>> <mailto:dgre...@apple.com>> wrote:
>>>>>>>> Or alternatively, one could decide to make the generics system *only 
>>>>>>>> and forever* work on nominal types, and make the syntactic sugar just 
>>>>>>>> be sugar for named types like Swift.Tuple, Function, and Optional.  
>>>>>>>> Either design could work.
>>>>>>> 
>>>>>>> We don’t have a way to make it work for function types, though, because 
>>>>>>> of parameter-passing conventions. Well, assuming we don’t invent 
>>>>>>> something that allows:
>>>>>>> 
>>>>>>>         Function<Double, inout String>
>>>>>>> 
>>>>>>> to exist in the type system. Tuple labels have a similar problem.
>>>>>> 
>>>>>> I’m totally aware of that and mentioned it upthread.
>>>>> 
>>>>> Eh, sorry I missed it.
>>>>> 
>>>>>>  There are various encoding tricks that could make this work depending 
>>>>>> on how you want to stretch the current generics system…
>>>>> 
>>>>> I think it’s straightforward and less ugly to make structural types allow 
>>>>> extensions and protocol conformances.
>>>> 
>>>> Can somebody explain to me what is less ugly about that? I would have 
>>>> naturally thought that the language would be simpler as a whole if there 
>>>> only existed nominal types and all structural types were just sugar over 
>>>> them.
>>> 
>>> What confuses me is that I always thought that T? was sugar for Optional<T> 
>>> by design, and found that to be quite elegant. But now you’re telling me 
>>> that its just a hack to allow conformance on Optionals until it can be made 
>>> structural. I would have thought that it would be cleaner to have specific 
>>> concepts (optionals, tuples, etc…) represented in terms of more general 
>>> concepts (enum, struct) so that the compiler had less to reason about. I’m 
>>> just trying to understand :-)
>> 
>> Don't worry too much about it.  The people in this thread are conflating a 
>> lot of different things, including some people who ought to know better.  
>> Your way of looking at it is perfectly accurate.
>> 
>> A fairly standard formalization of types is that you have these type 
>> expressions, which, in a simple system, are either type constants or type 
>> applications.
>> 
>> A type constant is something like Int, Float, or Array.  struct/enum/class 
>> declarations in Swift all introduce new type constants, where each 
>> declaration has its own identity as a type.  Since we don't allow type names 
>> to be redeclared in a scope, the identity of such declared types can be 
>> uniquely determined by (1) the type's name in its scope and (2) the path to 
>> that scope.  Hence the identity is "by name", or "nominal".
>> 
>> A type application takes a generic type and applies it at some number of 
>> arguments.  The general syntax for this in Swift is <>.  For example, Array 
>> is a generic type, and Array<Int> is a type application of the generic type 
>> Array with the argument Int.  The arguments can be arbitrary type 
>> expressions, e.g. Dictionary<String, Array<Float>>.  The identity of a type 
>> application is determined purely by its applicative structure: first, the 
>> identity of the generic type being applied, and second, the identity of the 
>> type arguments it is being applied to.  That is, A<B> is the same type as 
>> C<D> as long as the type-expression A is the same generic type as C and B is 
>> the same type as D.  Hence the identity is "structural".
>> 
>> (Formal nitpick: we're making some assumptions about the nature of type 
>> expressions that generally work out until you get into really advanced type 
>> systems.)
>> 
>> What is a tuple type in this formalization?  Well, the rule we want is that 
>> (A, B) is the same type as (C, D) if A is identical to C and B is identical 
>> to D.  We could add this as a special new rule to our definition of type 
>> expressions above, but we don't really need to, because it turns out that 
>> it's exactly the same as if we had some sort of tuple type constant — for 
>> sake of argument, let's call it (...) — and allowed it to be applied to an 
>> arbitrary number of types.  Swift does not actually allow you to name this 
>> as an unapplied generic type — you cannot write (...)<Int, Float> instead of 
>> (Int, Float) — but that's just a matter of syntax.  The fact that (...) is 
>> built into the language rather than being declared in the standard library 
>> as Tuple is not fundamentally significant.  Nor is it fundamentally 
>> significant for Optional, which is currently declared in the standard 
>> library instead of being built-in.
>> 
>> (Function types in Swift are weird because, as covered previously in this 
>> thread, there's more to their structure than just component type identity.  
>> You could still stretch the formalization to make this work, but, well, 
>> they'd still be weird.)
>> 
>> Now, function, tuple, and optional types are special in the language in 
>> several ways: there are primitive declarations and expressions that 
>> introduce or manipulate these types, and there are special rules in the type 
>> system for them.  (For example, optionals and tuples obey covariant 
>> subtyping.)  But we could technically do the same for any type if we wanted 
>> to.  We could even do it to arbitrary third-party types as long as we 
>> handled the possibility that they weren't imported into the current program.
>> 
>> We could absolutely allow tuples to conform to protocols without first 
>> introducing variadic generics.  We'd have to solve some straightforward 
>> internal representation problems, and then we'd just need some way of 
>> spelling them (if we didn't just hard-code a few conformances as special).
>> 
>> John.
> 
> Thanks for the lengthy explanation! I really appreciate the time taken to 
> educate.
> 
> When you say that we could allow tuples to conform to protocols without first 
> introducing Variadic Generics, it would still require some new syntax though? 
> Is that a complexity cost that would be reason enough to wait for the general 
> solution of Variadic Generics? Here, when I mention complexity, I’m talking 
> about the complexity of the language, not it’s implementation.

I think it would be difficult to allow useful user-defined 
extensions/conformances of arbitrary tuple types without variadic generics.  I 
think we could probably allow fixed-arity extensions/conformances more easily, 
but we'd run some complexity risk by encouraging people to make a bunch of 
conformances at different arities.  Either would require some substantial 
implementation effort, mostly around name lookup, which is currently heavily 
declaration-centric.

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

Reply via email to