> 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