Synthesizing Equatable, Hashable, and Comparable for tuple types

This is something I've wanted to look at for a while. A few weeks ago I pushed out https://github.com/apple/swift/pull/12598 to extend the existing synthesis to handle structs/enums when a field/payload has a tuple of things that are Equatable/Hashable, and in that PR it was (rightly) observed, as Chris just did, that making tuples conform to protocols would be a more general solution that solves the same problem you want to solve here.

I'd love to dig into this more, but last time I experimented with it I got stuck on places where the protocol conformance machinery expects NominalTypeDecls, and I wasn't sure where the right place to hoist that logic up to was (since tuples don't have a corresponding Decl from what I can tell). Any pointers?

Tuples won’t have a corresponding Decl, because they’re structural. The protocol conformance machinery (e.g., the ConformanceLookupTable) would need to be generalized to cover the various kinds of types that can be made to conform to a protocol: nominal types, function types, tuple types, metatypes, and protocol composition types. Similarly, the assumption that one can only write an extension on a nominal type is fairly widespread in the compiler.

All of these are fine refactors along the way, and could be used to improve the compiler long before we’re ready to turn it into a user-facing language feature.

  - Doug

···

On Nov 20, 2017, at 6:07 PM, Tony Allevato via swift-evolution <swift-evolution@swift.org> wrote:

On Mon, Nov 20, 2017 at 5:51 PM Chris Lattner via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
On Nov 20, 2017, at 5:48 PM, Kelvin Ma <kelvin13ma@gmail.com <mailto:kelvin13ma@gmail.com>> wrote:

the end goal here is to use tuples as a compatible currency type, to that end it makes sense for these three protocols to be handled as “compiler magic” and to disallow users from manually defining tuple conformances themselves. i’m not a fan of compiler magic, but Equatable, Hashable, and Comparable are special because they’re the basis for a lot of standard library functionality so i think the benefits of making this a special supported case outweigh the additional language opacity.

I understand your goal, but that compiler magic can’t exist until there is something to hook it into. Tuples can’t conform to protocols right now, so there is nothing that can be synthesized.

-Chris

On Mon, Nov 20, 2017 at 8:42 PM, Chris Lattner <clattner@nondot.org <mailto:clattner@nondot.org>> wrote:

On Nov 20, 2017, at 5:39 PM, Kelvin Ma via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

when SE-185 <https://github.com/apple/swift-evolution/blob/master/proposals/0185-synthesize-equatable-hashable.md> went through swift evolution, it was agreed that the next logical step <https://www.mail-archive.com/swift-evolution@swift.org/msg26162.html> is synthesizing these conformances for tuple types, though it was left out of the original proposal to avoid mission creep. I think now is the time to start thinking about this. i’m also tacking on Comparable to the other two protocols because there is precedent in the language from SE-15 <https://github.com/apple/swift-evolution/blob/master/proposals/0015-tuple-comparison-operators.md> that tuple comparison is something that makes sense to write.

EHC conformance is even more important for tuples than it is for structs because tuples effectively have no workaround whereas in structs, you could just manually implement the conformance.

In my opinion, you’re approaching this from the wrong direction. The fundamental problem here is that tuples can’t conform to a protocol. If they could, synthesizing these conformances would be straight-forward.

If you’re interested in pushing this forward, the discussion is “how do non-nominal types like tuples and functions conform to protocols”?

-Chris

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto: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

In Scala they just define Tuple1<A>, Tuple2<A, B>, ... up to 22 (I think). Eliminates the need for variadic generics and works fine in practice in Scala.

In Swift this approach is possibly unacceptable, since having to write:

    extension Tuple1 ...
    extension Tuple2 ...
    ...
    extension Tuple22 ...

Is a real pain.

However if we added variadic generics, Tuple<T...>, then we would also need a tuple to become a Collection (or some minimal subset of), e.g.:

    extension Tuple: Equatable where T: Equatable {
        static func == (lhs: Tuple, rhs: Tuple) -> Bool {
            guard lhs.count == rhs.count else {
                return false
            }
            for i in 0 ..< lhs.count {
                guard lhs[i] == rhs[i] else {
                    return false
                }
            }
            return true
        }
    }

Note how the tuple is treated like a collection. The compiler magic would be to make a Tuple a collection, which is more ‘magic’ than ‘magically’ adding Hashable :).

Despite the profusion of magic, variadic generics and Tuple collection additions are my favourite option.

-- Howard.

···

On 21 Nov 2017, at 1:17 pm, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

Yes, I agree, we need variadic generics before we can have tuples conform :frowning:

At the end of the day, you want to be able to treat “(U, V, W)” as sugar for Tuple<U,V,W> just like we handle array sugar. When that is possible, Tuple is just a type like any other in the system (but we need variadics to express it).

Once you have that, then you could write conformances in general, as well as conditional conformances that depend on (e.g.) all the element types being equatable.

We also need that to allow functions conform to protocols, because functions aren’t "T1->T2” objects, the actual parameter list is an inseparable part of the function type, and the parameter list needs variadics.

-Chris

On Nov 20, 2017, at 6:10 PM, Slava Pestov <spestov@apple.com> wrote:

Ignoring synthesized conformances for a second, think about how you would manually implement a conformance of a tuple type to a protocol. You would need some way to statically “iterate” over all the component types of the tuple — in fact this is the same as having variadic generics.

If we had variadic generics, we could implement tuples conforming to protocols, either by refactoring the compiler to allow conforming types to be non-nominal, or by reworking things so that a tuple is a nominal type with a single variadic generic parameter.

Slava

On Nov 20, 2017, at 9:06 PM, Tony Allevato via swift-evolution <swift-evolution@swift.org> wrote:

This is something I've wanted to look at for a while. A few weeks ago I pushed out https://github.com/apple/swift/pull/12598 to extend the existing synthesis to handle structs/enums when a field/payload has a tuple of things that are Equatable/Hashable, and in that PR it was (rightly) observed, as Chris just did, that making tuples conform to protocols would be a more general solution that solves the same problem you want to solve here.

I'd love to dig into this more, but last time I experimented with it I got stuck on places where the protocol conformance machinery expects NominalTypeDecls, and I wasn't sure where the right place to hoist that logic up to was (since tuples don't have a corresponding Decl from what I can tell). Any pointers?

On Mon, Nov 20, 2017 at 5:51 PM Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

On Nov 20, 2017, at 5:48 PM, Kelvin Ma <kelvin13ma@gmail.com> wrote:
the end goal here is to use tuples as a compatible currency type, to that end it makes sense for these three protocols to be handled as “compiler magic” and to disallow users from manually defining tuple conformances themselves. i’m not a fan of compiler magic, but Equatable, Hashable, and Comparable are special because they’re the basis for a lot of standard library functionality so i think the benefits of making this a special supported case outweigh the additional language opacity.

I understand your goal, but that compiler magic can’t exist until there is something to hook it into. Tuples can’t conform to protocols right now, so there is nothing that can be synthesized.

-Chris

On Mon, Nov 20, 2017 at 8:42 PM, Chris Lattner <clattner@nondot.org> wrote:

On Nov 20, 2017, at 5:39 PM, Kelvin Ma via swift-evolution <swift-evolution@swift.org> wrote:

when SE-185 went through swift evolution, it was agreed that the next logical step is synthesizing these conformances for tuple types, though it was left out of the original proposal to avoid mission creep. I think now is the time to start thinking about this. i’m also tacking on Comparable to the other two protocols because there is precedent in the language from SE-15 that tuple comparison is something that makes sense to write.

EHC conformance is even more important for tuples than it is for structs because tuples effectively have no workaround whereas in structs, you could just manually implement the conformance.

In my opinion, you’re approaching this from the wrong direction. The fundamental problem here is that tuples can’t conform to a protocol. If they could, synthesizing these conformances would be straight-forward.

If you’re interested in pushing this forward, the discussion is “how do non-nominal types like tuples and functions conform to protocols”?

-Chris

_______________________________________________
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

it’s ugly in C++ and disastrous in Swift because C++ has fixed layout
guarantees and everyone agrees that z comes after y comes after x, so you
can unsafe-bitcast the foreign C++ points into your own points “for free”.
you can’t do the same thing in Swift

···

On Thu, Nov 23, 2017 at 12:32 PM, Tino Heth <2th@gmx.de> wrote:

a good idea on paper, a disastrous one in practice. What happens if every
geometry library declares their own Point type?

That would be ugly („disastrous“ imho is a little bit to strong — C++
had/has similar issues, and other languages as well)
But if there would be a simple Point struct in a library that is popular
(could be achieved by shipping it alongside the stdlib), this problem would
be solved (there has been a pitch lately, but I guess it faded away
silently).

ps i remember that pitch because i’m pretty sure i was the one that pitched
that. consensus seemed it was too high level for inclusion (even though
having it at the stdlib level would do wonders for things like SIMD) and
everyone got distracted by “integers as generic parameters” (because we
love `Vector<3>` ig) because everything on this list always devolves into
“but this is *really* a problem with the *generics system*” and since no
one knows how to fix the generics system everyone calls it a day and
forgets about the original issue

···

On Thu, Nov 23, 2017 at 5:45 PM, Kelvin Ma <kelvin13ma@gmail.com> wrote:

On Thu, Nov 23, 2017 at 12:32 PM, Tino Heth <2th@gmx.de> wrote:

a good idea on paper, a disastrous one in practice. What happens if every
geometry library declares their own Point type?

That would be ugly („disastrous“ imho is a little bit to strong — C++
had/has similar issues, and other languages as well)
But if there would be a simple Point struct in a library that is popular
(could be achieved by shipping it alongside the stdlib), this problem would
be solved (there has been a pitch lately, but I guess it faded away
silently).

it’s ugly in C++ and disastrous in Swift because C++ has fixed layout
guarantees and everyone agrees that z comes after y comes after x, so you
can unsafe-bitcast the foreign C++ points into your own points “for free”.
you can’t do the same thing in Swift

Why do you need to have this ability to unsafe bitcast? Is interconversion
between point types such a common operation that it's a performance
bottleneck?

···

On Thu, Nov 23, 2017 at 16:45 Kelvin Ma via swift-evolution < swift-evolution@swift.org> wrote:

On Thu, Nov 23, 2017 at 12:32 PM, Tino Heth <2th@gmx.de> wrote:

a good idea on paper, a disastrous one in practice. What happens if every
geometry library declares their own Point type?

That would be ugly („disastrous“ imho is a little bit to strong — C++
had/has similar issues, and other languages as well)
But if there would be a simple Point struct in a library that is popular
(could be achieved by shipping it alongside the stdlib), this problem would
be solved (there has been a pitch lately, but I guess it faded away
silently).

it’s ugly in C++ and disastrous in Swift because C++ has fixed layout
guarantees and everyone agrees that z comes after y comes after x, so you
can unsafe-bitcast the foreign C++ points into your own points “for free”.
you can’t do the same thing in Swift

ps i remember that pitch because i’m pretty sure i was the one that pitched that.

No, I was writing about that one: https://www.mail-archive.com/swift-evolution@swift.org/msg30565.html

···

consensus seemed it was too high level for inclusion (even though having it at the stdlib level would do wonders for things like SIMD) and everyone got distracted by “integers as generic parameters” (because we love `Vector<3>` ig) because everything on this list always devolves into “but this is really a problem with the generics system” and since no one knows how to fix the generics system everyone calls it a day and forgets about the original issue

The expected behavior of tuple Equatable/Hashable/Comparable seems obvious to me (though I could well be missing something), and any behavior we hardcode should be naturally replaceable by a generalized conformance mechanism, so it's primarily a "small matter of implementation". There would be some implementation cost to managing the special case in the compiler and runtime; the tradeoff seems worth it to me in this case, but others might reasonably disagree. Not speaking for the entire core team, I would personally support considering a proposal and implementation for builtin tuple Equatable/Hashable/Comparable conformance.

-Joe

···

On Nov 28, 2017, at 10:52 AM, Vladimir.S <svabox@gmail.com> wrote:

On 27.11.2017 20:28, Joe Groff via swift-evolution wrote:

On Nov 20, 2017, at 5:43 PM, Chris Lattner via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Nov 20, 2017, at 5:39 PM, Kelvin Ma via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

when SE-185 <https://github.com/apple/swift-evolution/blob/master/proposals/0185-synthesize-equatable-hashable.md> went through swift evolution, it was agreed that the next logical step <https://www.mail-archive.com/swift-evolution@swift.org/msg26162.html> is synthesizing these conformances for tuple types, though it was left out of the original proposal to avoid mission creep. I think now is the time to start thinking about this. i’m also tacking on Comparable to the other two protocols because there is precedent in the language from SE-15 <https://github.com/apple/swift-evolution/blob/master/proposals/0015-tuple-comparison-operators.md> that tuple comparison is something that makes sense to write.

EHC conformance is even more important for tuples than it is for structs because tuples effectively have no workaround whereas in structs, you could just manually implement the conformance.

In my opinion, you’re approaching this from the wrong direction. The fundamental problem here is that tuples can’t conform to a protocol. If they could, synthesizing these conformances would be straight-forward.

It would be a tractable intermediate problem to introduce built-in conformances for tuples (and perhaps metatypes) to Equatable/Hashable/Comparable without breaching the more general topic of allowing these types to have general protocol conformances. I think that would cover the highest-value use cases.

So, shouldn't we do this first step ASAP and then design a good common solution to allow tuples/metatypes/funcs to confirm to custom protocols in some next version of Swift?
I really believe this is the good practical decision and will be supported by community if such proposal will be on the table.
Is there any drawback in such step?

i wouldn’t know how to implement this but i could write up this proposal in
a few days

···

On Tue, Nov 28, 2017 at 12:59 PM, Joe Groff via swift-evolution < swift-evolution@swift.org> wrote:

> On Nov 28, 2017, at 10:52 AM, Vladimir.S <svabox@gmail.com> wrote:
>
> On 27.11.2017 20:28, Joe Groff via swift-evolution wrote:
>>> On Nov 20, 2017, at 5:43 PM, Chris Lattner via swift-evolution < > swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>>>
>>>
>>>> On Nov 20, 2017, at 5:39 PM, Kelvin Ma via swift-evolution < > swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>>>>
>>>> when SE-185 <https://github.com/apple/swift-evolution/blob/master/
proposals/0185-synthesize-equatable-hashable.md> went through swift
evolution, it was agreed that the next logical step <
https://www.mail-archive.com/swift-evolution@swift.org/msg26162.html> is
synthesizing these conformances for tuple types, though it was left out of
the original proposal to avoid mission creep. I think now is the time to
start thinking about this. i’m also tacking on Comparable to the other two
protocols because there is precedent in the language from SE-15 <
https://github.com/apple/swift-evolution/blob/master/proposals/0015-tuple-
comparison-operators.md> that tuple comparison is something that makes
sense to write.
>>>>
>>>> EHC conformance is even more important for tuples than it is for
structs because tuples effectively have no workaround whereas in structs,
you could just manually implement the conformance.
>>>
>>> In my opinion, you’re approaching this from the wrong direction. The
fundamental problem here is that tuples can’t conform to a protocol. If
they could, synthesizing these conformances would be straight-forward.
>> It would be a tractable intermediate problem to introduce built-in
conformances for tuples (and perhaps metatypes) to
Equatable/Hashable/Comparable without breaching the more general topic of
allowing these types to have general protocol conformances. I think that
would cover the highest-value use cases.
>
> So, shouldn't we do this first step ASAP and then design a good common
solution to allow tuples/metatypes/funcs to confirm to custom protocols in
some next version of Swift?
> I really believe this is the good practical decision and will be
supported by community if such proposal will be on the table.
> Is there any drawback in such step?

The expected behavior of tuple Equatable/Hashable/Comparable seems obvious
to me (though I could well be missing something), and any behavior we
hardcode should be naturally replaceable by a generalized conformance
mechanism, so it's primarily a "small matter of implementation". There
would be some implementation cost to managing the special case in the
compiler and runtime; the tradeoff seems worth it to me in this case, but
others might reasonably disagree. Not speaking for the entire core team, I
would personally support considering a proposal and implementation for
builtin tuple Equatable/Hashable/Comparable conformance.

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

+1. It seems like a practical first step.

···

On Nov 28, 2017, at 10:59 AM, Joe Groff via swift-evolution <swift-evolution@swift.org> wrote:

On Nov 28, 2017, at 10:52 AM, Vladimir.S <svabox@gmail.com> wrote:

On 27.11.2017 20:28, Joe Groff via swift-evolution wrote:

On Nov 20, 2017, at 5:43 PM, Chris Lattner via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Nov 20, 2017, at 5:39 PM, Kelvin Ma via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

when SE-185 <https://github.com/apple/swift-evolution/blob/master/proposals/0185-synthesize-equatable-hashable.md> went through swift evolution, it was agreed that the next logical step <https://www.mail-archive.com/swift-evolution@swift.org/msg26162.html> is synthesizing these conformances for tuple types, though it was left out of the original proposal to avoid mission creep. I think now is the time to start thinking about this. i’m also tacking on Comparable to the other two protocols because there is precedent in the language from SE-15 <https://github.com/apple/swift-evolution/blob/master/proposals/0015-tuple-comparison-operators.md> that tuple comparison is something that makes sense to write.

EHC conformance is even more important for tuples than it is for structs because tuples effectively have no workaround whereas in structs, you could just manually implement the conformance.

In my opinion, you’re approaching this from the wrong direction. The fundamental problem here is that tuples can’t conform to a protocol. If they could, synthesizing these conformances would be straight-forward.

It would be a tractable intermediate problem to introduce built-in conformances for tuples (and perhaps metatypes) to Equatable/Hashable/Comparable without breaching the more general topic of allowing these types to have general protocol conformances. I think that would cover the highest-value use cases.

So, shouldn't we do this first step ASAP and then design a good common solution to allow tuples/metatypes/funcs to confirm to custom protocols in some next version of Swift?
I really believe this is the good practical decision and will be supported by community if such proposal will be on the table.
Is there any drawback in such step?

The expected behavior of tuple Equatable/Hashable/Comparable seems obvious to me (though I could well be missing something), and any behavior we hardcode should be naturally replaceable by a generalized conformance mechanism, so it's primarily a "small matter of implementation". There would be some implementation cost to managing the special case in the compiler and runtime; the tradeoff seems worth it to me in this case, but others might reasonably disagree. Not speaking for the entire core team, I would personally support considering a proposal and implementation for builtin tuple Equatable/Hashable/Comparable conformance.

-Joe
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

>
>>>
>>>
>>>>
>>>> when SE-185 <
https://github.com/apple/swift-evolution/blob/master/proposals/0185-synthesize-equatable-hashable.md>
went through swift evolution, it was agreed that the next logical step <
https://www.mail-archive.com/swift-evolution@swift.org/msg26162.html> is
synthesizing these conformances for tuple types, though it was left out of
the original proposal to avoid mission creep. I think now is the time to
start thinking about this. i’m also tacking on Comparable to the other two
protocols because there is precedent in the language from SE-15 <
https://github.com/apple/swift-evolution/blob/master/proposals/0015-tuple-comparison-operators.md>
that tuple comparison is something that makes sense to write.
>>>>
>>>> EHC conformance is even more important for tuples than it is for
structs because tuples effectively have no workaround whereas in structs,
you could just manually implement the conformance.
>>>
>>> In my opinion, you’re approaching this from the wrong direction. The
fundamental problem here is that tuples can’t conform to a protocol. If
they could, synthesizing these conformances would be straight-forward.
>> It would be a tractable intermediate problem to introduce built-in
conformances for tuples (and perhaps metatypes) to
Equatable/Hashable/Comparable without breaching the more general topic of
allowing these types to have general protocol conformances. I think that
would cover the highest-value use cases.
>
> So, shouldn't we do this first step ASAP and then design a good common
solution to allow tuples/metatypes/funcs to confirm to custom protocols in
some next version of Swift?
> I really believe this is the good practical decision and will be
supported by community if such proposal will be on the table.
> Is there any drawback in such step?

The expected behavior of tuple Equatable/Hashable/Comparable seems
obvious to me (though I could well be missing something), and any behavior
we hardcode should be naturally replaceable by a generalized conformance
mechanism, so it's primarily a "small matter of implementation". There
would be some implementation cost to managing the special case in the
compiler and runtime; the tradeoff seems worth it to me in this case, but
others might reasonably disagree. Not speaking for the entire core team, I
would personally support considering a proposal and implementation for
builtin tuple Equatable/Hashable/Comparable conformance.

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

i wouldn’t know how to implement this but i could write up this proposal
in a few days

I've been looking the past couple days at how to generalize the protocol
conformance machinery to support structural types (even if we don't support
arbitrary conformance syntactically, at least being able to hardcode the
ones we want to synthesize initially). My free time isn't exactly
plentiful, but I'm hoping to make some decent progress, so I'm happy to
help where I can on this since it's a natural follow-up to my other
Equatable/Hashable work!

···

On Tue, Nov 28, 2017 at 11:23 AM Kelvin Ma via swift-evolution < swift-evolution@swift.org> wrote:

On Tue, Nov 28, 2017 at 12:59 PM, Joe Groff via swift-evolution < > swift-evolution@swift.org> wrote:

> On Nov 28, 2017, at 10:52 AM, Vladimir.S <svabox@gmail.com> wrote:
> On 27.11.2017 20:28, Joe Groff via swift-evolution wrote:
>>> On Nov 20, 2017, at 5:43 PM, Chris Lattner via swift-evolution < >> swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>>>> On Nov 20, 2017, at 5:39 PM, Kelvin Ma via swift-evolution < >> swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

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

So (borrowing C++-ish notation), a function of type `(Args...) -> Result` would become sugar for something like `Function<Args..., Result>`? That certainly makes sense.

Yep

How would throw-ness be handled—would we need ThrowingFunction and Function, with the ability to coerce Function -> ThrowingFunction? (Async might pose similar issues?)

Right, there are several ways we could express that which would have to be designed. There are other questions as well: e.g. how do we represent inout?

-Chris

···

On Nov 20, 2017, at 6:31 PM, Tony Allevato <tony.allevato@gmail.com> wrote:

Yes, I agree, we need variadic generics before we can have tuples conform :frowning:

At the end of the day, you want to be able to treat “(U, V, W)” as sugar for Tuple<U,V,W> just like we handle array sugar. When that is possible, Tuple is just a type like any other in the system (but we need variadics to express it).

Eye-opening! Now I understand how important variadic generics are. Somebody should add that example to the Generics Manifesto. Questions:

• Doesn’t this simplification of the type system hoist Variadic Generics back up the list of priorities?

Not above conditional and recursive conformances.

• Would it be desirable to implement them before ABI stability to “remove” tuples from the ABI?
• If not, is the current ABI already flexible enough to support them if they are implemented later on?

I am not the expert on this (Doug Gregor is), but I think we can add it later in an ABI additive way.

-Chris

···

On Nov 20, 2017, at 10:24 PM, David Hart <david@hartbit.com> wrote:
On 21 Nov 2017, at 03:17, Chris Lattner via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Once you have that, then you could write conformances in general, as well as conditional conformances that depend on (e.g.) all the element types being equatable.

We also need that to allow functions conform to protocols, because functions aren’t "T1->T2” objects, the actual parameter list is an inseparable part of the function type, and the parameter list needs variadics.

-Chris

On Nov 20, 2017, at 6:10 PM, Slava Pestov <spestov@apple.com <mailto:spestov@apple.com>> wrote:

Ignoring synthesized conformances for a second, think about how you would manually implement a conformance of a tuple type to a protocol. You would need some way to statically “iterate” over all the component types of the tuple — in fact this is the same as having variadic generics.

If we had variadic generics, we could implement tuples conforming to protocols, either by refactoring the compiler to allow conforming types to be non-nominal, or by reworking things so that a tuple is a nominal type with a single variadic generic parameter.

Slava

On Nov 20, 2017, at 9:06 PM, Tony Allevato via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

This is something I've wanted to look at for a while. A few weeks ago I pushed out https://github.com/apple/swift/pull/12598 to extend the existing synthesis to handle structs/enums when a field/payload has a tuple of things that are Equatable/Hashable, and in that PR it was (rightly) observed, as Chris just did, that making tuples conform to protocols would be a more general solution that solves the same problem you want to solve here.

I'd love to dig into this more, but last time I experimented with it I got stuck on places where the protocol conformance machinery expects NominalTypeDecls, and I wasn't sure where the right place to hoist that logic up to was (since tuples don't have a corresponding Decl from what I can tell). Any pointers?

On Mon, Nov 20, 2017 at 5:51 PM Chris Lattner via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
On Nov 20, 2017, at 5:48 PM, Kelvin Ma <kelvin13ma@gmail.com <mailto:kelvin13ma@gmail.com>> wrote:

the end goal here is to use tuples as a compatible currency type, to that end it makes sense for these three protocols to be handled as “compiler magic” and to disallow users from manually defining tuple conformances themselves. i’m not a fan of compiler magic, but Equatable, Hashable, and Comparable are special because they’re the basis for a lot of standard library functionality so i think the benefits of making this a special supported case outweigh the additional language opacity.

I understand your goal, but that compiler magic can’t exist until there is something to hook it into. Tuples can’t conform to protocols right now, so there is nothing that can be synthesized.

-Chris

On Mon, Nov 20, 2017 at 8:42 PM, Chris Lattner <clattner@nondot.org <mailto:clattner@nondot.org>> wrote:

On Nov 20, 2017, at 5:39 PM, Kelvin Ma via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

when SE-185 <https://github.com/apple/swift-evolution/blob/master/proposals/0185-synthesize-equatable-hashable.md> went through swift evolution, it was agreed that the next logical step <https://www.mail-archive.com/swift-evolution@swift.org/msg26162.html> is synthesizing these conformances for tuple types, though it was left out of the original proposal to avoid mission creep. I think now is the time to start thinking about this. i’m also tacking on Comparable to the other two protocols because there is precedent in the language from SE-15 <https://github.com/apple/swift-evolution/blob/master/proposals/0015-tuple-comparison-operators.md> that tuple comparison is something that makes sense to write.

EHC conformance is even more important for tuples than it is for structs because tuples effectively have no workaround whereas in structs, you could just manually implement the conformance.

In my opinion, you’re approaching this from the wrong direction. The fundamental problem here is that tuples can’t conform to a protocol. If they could, synthesizing these conformances would be straight-forward.

If you’re interested in pushing this forward, the discussion is “how do non-nominal types like tuples and functions conform to protocols”?

-Chris

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

Yes, I agree, we need variadic generics before we can have tuples conform :frowning:

At the end of the day, you want to be able to treat “(U, V, W)” as sugar for Tuple<U,V,W> just like we handle array sugar. When that is possible, Tuple is just a type like any other in the system (but we need variadics to express it).

Eye-opening! Now I understand how important variadic generics are. Somebody should add that example to the Generics Manifesto.

It’s in there under “extensions of structural types”, here: https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#extensions-of-structural-types

with this example:

  extension<...Elements : Equatable> (Elements...) : Equatable { // extending the tuple type "(Elements...)" to be Equatable
}

Questions:

• Doesn’t this simplification of the type system hoist Variadic Generics back up the list of priorities?

Not above conditional and recursive conformances.

Right, and we don’t have bandwidth to take on Another Major Generics Feature this year.

• Would it be desirable to implement them before ABI stability to “remove” tuples from the ABI?

Tuples are structural types in the ABI (and type system), and should remain that way. So, I disagree with Chris’s suggestion that (U, V, W) will become Tuple<U, V, W>. The most relevant comparison today is Optional, which is technically a nominal type but is treated as a special case basically everywhere in the compiler (and ABI) because it should have been a structural type. I expect optionals to become structural types in the future (the ABI is designed for that) and tuples to remain structural types.

• If not, is the current ABI already flexible enough to support them if they are implemented later on?

I am not the expert on this (Doug Gregor is), but I think we can add it later in an ABI additive way.

Yes, we can add it to the ABI later.

  - Doug

···

On Nov 20, 2017, at 10:31 PM, Chris Lattner <clattner@nondot.org> wrote:

On Nov 20, 2017, at 10:24 PM, David Hart <david@hartbit.com <mailto:david@hartbit.com>> wrote:
On 21 Nov 2017, at 03:17, Chris Lattner via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

-Chris

Once you have that, then you could write conformances in general, as well as conditional conformances that depend on (e.g.) all the element types being equatable.

We also need that to allow functions conform to protocols, because functions aren’t "T1->T2” objects, the actual parameter list is an inseparable part of the function type, and the parameter list needs variadics.

-Chris

On Nov 20, 2017, at 6:10 PM, Slava Pestov <spestov@apple.com <mailto:spestov@apple.com>> wrote:

Ignoring synthesized conformances for a second, think about how you would manually implement a conformance of a tuple type to a protocol. You would need some way to statically “iterate” over all the component types of the tuple — in fact this is the same as having variadic generics.

If we had variadic generics, we could implement tuples conforming to protocols, either by refactoring the compiler to allow conforming types to be non-nominal, or by reworking things so that a tuple is a nominal type with a single variadic generic parameter.

Slava

On Nov 20, 2017, at 9:06 PM, Tony Allevato via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

This is something I've wanted to look at for a while. A few weeks ago I pushed out https://github.com/apple/swift/pull/12598 to extend the existing synthesis to handle structs/enums when a field/payload has a tuple of things that are Equatable/Hashable, and in that PR it was (rightly) observed, as Chris just did, that making tuples conform to protocols would be a more general solution that solves the same problem you want to solve here.

I'd love to dig into this more, but last time I experimented with it I got stuck on places where the protocol conformance machinery expects NominalTypeDecls, and I wasn't sure where the right place to hoist that logic up to was (since tuples don't have a corresponding Decl from what I can tell). Any pointers?

On Mon, Nov 20, 2017 at 5:51 PM Chris Lattner via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
On Nov 20, 2017, at 5:48 PM, Kelvin Ma <kelvin13ma@gmail.com <mailto:kelvin13ma@gmail.com>> wrote:

the end goal here is to use tuples as a compatible currency type, to that end it makes sense for these three protocols to be handled as “compiler magic” and to disallow users from manually defining tuple conformances themselves. i’m not a fan of compiler magic, but Equatable, Hashable, and Comparable are special because they’re the basis for a lot of standard library functionality so i think the benefits of making this a special supported case outweigh the additional language opacity.

I understand your goal, but that compiler magic can’t exist until there is something to hook it into. Tuples can’t conform to protocols right now, so there is nothing that can be synthesized.

-Chris

On Mon, Nov 20, 2017 at 8:42 PM, Chris Lattner <clattner@nondot.org <mailto:clattner@nondot.org>> wrote:

On Nov 20, 2017, at 5:39 PM, Kelvin Ma via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

when SE-185 <https://github.com/apple/swift-evolution/blob/master/proposals/0185-synthesize-equatable-hashable.md> went through swift evolution, it was agreed that the next logical step <https://www.mail-archive.com/swift-evolution@swift.org/msg26162.html> is synthesizing these conformances for tuple types, though it was left out of the original proposal to avoid mission creep. I think now is the time to start thinking about this. i’m also tacking on Comparable to the other two protocols because there is precedent in the language from SE-15 <https://github.com/apple/swift-evolution/blob/master/proposals/0015-tuple-comparison-operators.md> that tuple comparison is something that makes sense to write.

EHC conformance is even more important for tuples than it is for structs because tuples effectively have no workaround whereas in structs, you could just manually implement the conformance.

In my opinion, you’re approaching this from the wrong direction. The fundamental problem here is that tuples can’t conform to a protocol. If they could, synthesizing these conformances would be straight-forward.

If you’re interested in pushing this forward, the discussion is “how do non-nominal types like tuples and functions conform to protocols”?

-Chris

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

In Scala they just define Tuple1<A>, Tuple2<A, B>, ... up to 22 (I think).
Eliminates the need for variadic generics and works fine in practice in
Scala.

In Swift this approach is possibly unacceptable, since having to write:

    extension Tuple1 ...
    extension Tuple2 ...
    ...
    extension Tuple22 ...

Is a real pain.

However if we added variadic generics, Tuple<T...>, then we would also
need a tuple to become a Collection (or some minimal subset of), e.g.:

    extension Tuple: Equatable where T: Equatable {
        static func == (lhs: Tuple, rhs: Tuple) -> Bool {
            guard lhs.count == rhs.count else {
                return false
            }
            for i in 0 ..< lhs.count {
                guard lhs[i] == rhs[i] else {
                    return false
                }
            }
            return true
        }
    }

It's a bit more complex than that—saying `where T: Equatable` feels off
because `T` here isn't a single type. A syntax like `T...: Equatable` to
mean "all arguments in the parameter pack conform to Equatable" might be
clearer.

Adding Collection conformance is also problematic because tuples can be
heterogeneous. If you have Tuple<Int, String, SomeClass>, what's the type
of lhs[i]? It depends on i, which isn't going to work.

We'd probably need some syntax for destructuring tuples into a "first"
element and "rest" tuple of arity N–1 so that equality (and other
operations) could be implemented recursively, statically at compile time.

Of course, all of this gets dangerously into the realm of C++ template
metaprogramming horrors. :slight_smile: Hopefully we can come up with less obtuse
solutions/syntax for Swift.

···

On Tue, Nov 21, 2017 at 8:43 AM Howard Lovatt via swift-evolution < swift-evolution@swift.org> wrote:

Note how the tuple is treated like a collection. The compiler magic would
be to make a Tuple a collection, which is more ‘magic’ than ‘magically’
adding Hashable :).

Despite the profusion of magic, variadic generics and Tuple collection
additions are my favourite option.

-- Howard.

On 21 Nov 2017, at 1:17 pm, Chris Lattner via swift-evolution < > swift-evolution@swift.org> wrote:

Yes, I agree, we need variadic generics before we can have tuples conform
:frowning:

At the end of the day, you want to be able to treat “(U, V, W)” as sugar
for Tuple<U,V,W> just like we handle array sugar. When that is possible,
Tuple is just a type like any other in the system (but we need variadics to
express it).

Once you have that, then you could write conformances in general, as well
as conditional conformances that depend on (e.g.) all the element types
being equatable.

We also need that to allow functions conform to protocols, because
functions aren’t "T1->T2” objects, the actual parameter list is an
inseparable part of the function type, and the parameter list needs
variadics.

-Chris

On Nov 20, 2017, at 6:10 PM, Slava Pestov <spestov@apple.com> wrote:

Ignoring synthesized conformances for a second, think about how you would
manually implement a conformance of a tuple type to a protocol. You would
need some way to statically “iterate” over all the component types of the
tuple — in fact this is the same as having variadic generics.

If we had variadic generics, we could implement tuples conforming to
protocols, either by refactoring the compiler to allow conforming types to
be non-nominal, or by reworking things so that a tuple is a nominal type
with a single variadic generic parameter.

Slava

On Nov 20, 2017, at 9:06 PM, Tony Allevato via swift-evolution < > swift-evolution@swift.org> wrote:

This is something I've wanted to look at for a while. A few weeks ago I
pushed out https://github.com/apple/swift/pull/12598 to extend the
existing synthesis to handle structs/enums when a field/payload has a tuple
of things that are Equatable/Hashable, and in that PR it was (rightly)
observed, as Chris just did, that making tuples conform to protocols would
be a more general solution that solves the same problem you want to solve
here.

I'd love to dig into this more, but last time I experimented with it I got
stuck on places where the protocol conformance machinery expects
NominalTypeDecls, and I wasn't sure where the right place to hoist that
logic up to was (since tuples don't have a corresponding Decl from what I
can tell). Any pointers?

On Mon, Nov 20, 2017 at 5:51 PM Chris Lattner via swift-evolution < > swift-evolution@swift.org> wrote:

On Nov 20, 2017, at 5:48 PM, Kelvin Ma <kelvin13ma@gmail.com> wrote:

the end goal here is to use tuples as a compatible currency type, to that
end it makes sense for these three protocols to be handled as “compiler
magic” and to disallow users from manually defining tuple conformances
themselves. i’m not a fan of compiler magic, but Equatable, Hashable, and
Comparable are special because they’re the basis for a lot of standard
library functionality so i think the benefits of making this a special
supported case outweigh the additional language opacity.

I understand your goal, but that compiler magic can’t exist until there
is something to hook it into. Tuples can’t conform to protocols right now,
so there is nothing that can be synthesized.

-Chris

On Mon, Nov 20, 2017 at 8:42 PM, Chris Lattner <clattner@nondot.org> >> wrote:

On Nov 20, 2017, at 5:39 PM, Kelvin Ma via swift-evolution < >>> swift-evolution@swift.org> wrote:

when SE-185
<https://github.com/apple/swift-evolution/blob/master/proposals/0185-synthesize-equatable-hashable.md>
went through swift evolution, it was agreed that the next logical step
<https://www.mail-archive.com/swift-evolution@swift.org/msg26162.html>
is synthesizing these conformances for tuple types, though it was left out
of the original proposal to avoid mission creep. I think now is the time to
start thinking about this. i’m also tacking on Comparable to the other
two protocols because there is precedent in the language from SE-15
<https://github.com/apple/swift-evolution/blob/master/proposals/0015-tuple-comparison-operators.md>
that tuple comparison is something that makes sense to write.

EHC conformance is even more important for tuples than it is for structs
because tuples effectively have no workaround whereas in structs, you could
just manually implement the conformance.

In my opinion, you’re approaching this from the wrong direction. The
fundamental problem here is that tuples can’t conform to a protocol. If
they could, synthesizing these conformances would be straight-forward.

If you’re interested in pushing this forward, the discussion is “how do
non-nominal types like tuples and functions conform to protocols”?

-Chris

_______________________________________________
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

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

Yes, I agree, we need variadic generics before we can have tuples conform :frowning:

At the end of the day, you want to be able to treat “(U, V, W)” as sugar for Tuple<U,V,W> just like we handle array sugar. When that is possible, Tuple is just a type like any other in the system (but we need variadics to express it).

Eye-opening! Now I understand how important variadic generics are. Somebody should add that example to the Generics Manifesto. Questions:

• Doesn’t this simplification of the type system hoist Variadic Generics back up the list of priorities?

Not above conditional and recursive conformances.

Correct. But recursive conformances are implemented and conditional conformances are on the way. To rephrase my question: doesn't this simplification of the type system hoist Variadic Generics to be the next big priority after conditional conformances are finished?

···

On 21 Nov 2017, at 07:31, Chris Lattner <clattner@nondot.org> wrote:

On Nov 20, 2017, at 10:24 PM, David Hart <david@hartbit.com <mailto:david@hartbit.com>> wrote:
On 21 Nov 2017, at 03:17, Chris Lattner via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

• Would it be desirable to implement them before ABI stability to “remove” tuples from the ABI?
• If not, is the current ABI already flexible enough to support them if they are implemented later on?

I am not the expert on this (Doug Gregor is), but I think we can add it later in an ABI additive way.

-Chris

Once you have that, then you could write conformances in general, as well as conditional conformances that depend on (e.g.) all the element types being equatable.

We also need that to allow functions conform to protocols, because functions aren’t "T1->T2” objects, the actual parameter list is an inseparable part of the function type, and the parameter list needs variadics.

-Chris

On Nov 20, 2017, at 6:10 PM, Slava Pestov <spestov@apple.com <mailto:spestov@apple.com>> wrote:

Ignoring synthesized conformances for a second, think about how you would manually implement a conformance of a tuple type to a protocol. You would need some way to statically “iterate” over all the component types of the tuple — in fact this is the same as having variadic generics.

If we had variadic generics, we could implement tuples conforming to protocols, either by refactoring the compiler to allow conforming types to be non-nominal, or by reworking things so that a tuple is a nominal type with a single variadic generic parameter.

Slava

On Nov 20, 2017, at 9:06 PM, Tony Allevato via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

This is something I've wanted to look at for a while. A few weeks ago I pushed out https://github.com/apple/swift/pull/12598 to extend the existing synthesis to handle structs/enums when a field/payload has a tuple of things that are Equatable/Hashable, and in that PR it was (rightly) observed, as Chris just did, that making tuples conform to protocols would be a more general solution that solves the same problem you want to solve here.

I'd love to dig into this more, but last time I experimented with it I got stuck on places where the protocol conformance machinery expects NominalTypeDecls, and I wasn't sure where the right place to hoist that logic up to was (since tuples don't have a corresponding Decl from what I can tell). Any pointers?

On Mon, Nov 20, 2017 at 5:51 PM Chris Lattner via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
On Nov 20, 2017, at 5:48 PM, Kelvin Ma <kelvin13ma@gmail.com <mailto:kelvin13ma@gmail.com>> wrote:

the end goal here is to use tuples as a compatible currency type, to that end it makes sense for these three protocols to be handled as “compiler magic” and to disallow users from manually defining tuple conformances themselves. i’m not a fan of compiler magic, but Equatable, Hashable, and Comparable are special because they’re the basis for a lot of standard library functionality so i think the benefits of making this a special supported case outweigh the additional language opacity.

I understand your goal, but that compiler magic can’t exist until there is something to hook it into. Tuples can’t conform to protocols right now, so there is nothing that can be synthesized.

-Chris

On Mon, Nov 20, 2017 at 8:42 PM, Chris Lattner <clattner@nondot.org <mailto:clattner@nondot.org>> wrote:

On Nov 20, 2017, at 5:39 PM, Kelvin Ma via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

when SE-185 <https://github.com/apple/swift-evolution/blob/master/proposals/0185-synthesize-equatable-hashable.md> went through swift evolution, it was agreed that the next logical step <https://www.mail-archive.com/swift-evolution@swift.org/msg26162.html> is synthesizing these conformances for tuple types, though it was left out of the original proposal to avoid mission creep. I think now is the time to start thinking about this. i’m also tacking on Comparable to the other two protocols because there is precedent in the language from SE-15 <https://github.com/apple/swift-evolution/blob/master/proposals/0015-tuple-comparison-operators.md> that tuple comparison is something that makes sense to write.

EHC conformance is even more important for tuples than it is for structs because tuples effectively have no workaround whereas in structs, you could just manually implement the conformance.

In my opinion, you’re approaching this from the wrong direction. The fundamental problem here is that tuples can’t conform to a protocol. If they could, synthesizing these conformances would be straight-forward.

If you’re interested in pushing this forward, the discussion is “how do non-nominal types like tuples and functions conform to protocols”?

-Chris

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

idk if it’s a performance bottleneck because i use tuples in my geometry
stack and i keep the bottom 2 levels in the same module but it cannot be
good. a lot of the geometry code I write sits atop 2 or 3 other layers of
geometry code beneath it, and it interops with geometry APIs in other
libraries. for example it might be organized like

[ Client geometry code ] ←→ [ Library geometry code ] (example:
Voronoi.voronoi(_:), Noise.perlin(_:_:))
       [ Procedurally generated geometry ] (example:
makeSphere(resolution:))
       [ Matrices and projections ] (example:
Geometry.clockwise(_:_:center:normal:))
       [ Math ] (example: Math.cross(_:_:))

converting at every boundary seems like something to avoid. not to mention
the sheer amount of boilerplate all those conversions produce.

···

On Thu, Nov 23, 2017 at 7:08 PM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

On Thu, Nov 23, 2017 at 16:45 Kelvin Ma via swift-evolution < > swift-evolution@swift.org> wrote:

On Thu, Nov 23, 2017 at 12:32 PM, Tino Heth <2th@gmx.de> wrote:

a good idea on paper, a disastrous one in practice. What happens if
every geometry library declares their own Point type?

That would be ugly („disastrous“ imho is a little bit to strong — C++
had/has similar issues, and other languages as well)
But if there would be a simple Point struct in a library that is popular
(could be achieved by shipping it alongside the stdlib), this problem would
be solved (there has been a pitch lately, but I guess it faded away
silently).

it’s ugly in C++ and disastrous in Swift because C++ has fixed layout
guarantees and everyone agrees that z comes after y comes after x, so you
can unsafe-bitcast the foreign C++ points into your own points “for free”.
you can’t do the same thing in Swift

Why do you need to have this ability to unsafe bitcast? Is interconversion
between point types such a common operation that it's a performance
bottleneck?

FWIW, tuples are only guaranteed to have a C-compatible layout when exposed
to C; that is, Swift doesn't guarantee that there will not be optimizations
in the future that change tuple layout such that a call into C will cause
your tuples to do interop gymnastics.

···

On Thu, Nov 23, 2017 at 6:27 PM, Kelvin Ma <kelvin13ma@gmail.com> wrote:

On Thu, Nov 23, 2017 at 7:08 PM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

On Thu, Nov 23, 2017 at 16:45 Kelvin Ma via swift-evolution < >> swift-evolution@swift.org> wrote:

On Thu, Nov 23, 2017 at 12:32 PM, Tino Heth <2th@gmx.de> wrote:

a good idea on paper, a disastrous one in practice. What happens if
every geometry library declares their own Point type?

That would be ugly („disastrous“ imho is a little bit to strong — C++
had/has similar issues, and other languages as well)
But if there would be a simple Point struct in a library that is
popular (could be achieved by shipping it alongside the stdlib), this
problem would be solved (there has been a pitch lately, but I guess it
faded away silently).

it’s ugly in C++ and disastrous in Swift because C++ has fixed layout
guarantees and everyone agrees that z comes after y comes after x, so you
can unsafe-bitcast the foreign C++ points into your own points “for free”.
you can’t do the same thing in Swift

Why do you need to have this ability to unsafe bitcast? Is
interconversion between point types such a common operation that it's a
performance bottleneck?

idk if it’s a performance bottleneck because i use tuples in my geometry
stack and i keep the bottom 2 levels in the same module but it cannot be
good. a lot of the geometry code I write sits atop 2 or 3 other layers of
geometry code beneath it, and it interops with geometry APIs in other
libraries. for example it might be organized like

[ Client geometry code ] ←→ [ Library geometry code ] (example:
Voronoi.voronoi(_:), Noise.perlin(_:_:))
       [ Procedurally generated geometry ] (example:
makeSphere(resolution:))
       [ Matrices and projections ] (example:
Geometry.clockwise(_:_:center:normal:))
       [ Math ] (example: Math.cross(_:_:))

converting at every boundary seems like something to avoid. not to mention
the sheer amount of boilerplate all those conversions produce.

Why do you need to have this ability to unsafe bitcast? Is interconversion between point types such a common operation that it's a performance bottleneck?

A real-world example: Real-time image processing.
When you have a stream of 4k pictures at 30 fps, you really don’t wont to copy buffers just because two filters insist on having their own representation of bitmap data.

“*write it in c and import it*” is *not* a solution, it is a workaround.
plus since it lives across the module boundary, it’s effectively opaque to
compiler optimizations.

···

On Mon, Nov 27, 2017 at 9:43 PM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

On Mon, Nov 27, 2017 at 5:56 PM, Kelvin Ma <kelvin13ma@gmail.com> wrote:

On Mon, Nov 27, 2017 at 4:21 PM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

On Mon, Nov 27, 2017 at 15:46 Taylor Swift <kelvin13ma@gmail.com> wrote:

they use packed buffers of floats, which for type safety are better
rebound to a structured type. right now (Float, Float, Float) works because
the tuple is laid out contiguously and the GPU can’t tell the difference
but it’s not guaranteed. also you’re ignoring all the CPU stages that occur
before anything even gets sent to the GPU.

Precisely, there is no guarantee of performance if you call these APIs
with an array of Swift tuples.

which is exactly why i support a dedicated language-level vector type
which guarantees contiguous, fixed storage, and which the compiler knows
about so it can vectorize operations on them.

That's an entirely separate discussion.

tuples right now try to fill too many roles and that makes life difficult
for both the compiler and the programmer. however, until then, we need some
kind of common, fixed layout currency type for vector data, and by
implementation-detail, *tuples are our best option* since for some
reason everyone is so opposed to the simple solution of baking vec2, vec3,
… vec5 into the language and the generic integer Vector<Float, k>
solution everyone wants likely isn’t going to materialize for the
foreseeable future.

Disagree. If you want a particular memory layout, define your type in C.
Swift's interop story is very good, and your type will have a fixed layout
forever.

If I were going to look into implementing this, my first-pass approach would be something like this. It's not necessarily the best or most optimal approach, but it might get you started:

- Introduce a new ProtocolConformance subclass for tuple conformances, that collects the required protocol conformances from all the elements
- Enhance the AST and type checker conformance lookup machinery, such as lookupConformance and conformsToProtocol, to work with tuples, by returning TupleProtocolConformances where applicable
- In IRGen, lower a reference to a TupleProtocolConformance into a runtime call that grabs the conformance for a tuple type to a given protocol with the given element conformances
- In the runtime, implement these runtime calls similar to how we generate structural type metadata, with a uniquing cache that instantiates a unique witness table for each unique (type, element conformances...) key. It should be possible to implement the witness methods themselves in C++ in a way that works dynamically with any tuple type.

There might be follow-up work we'd want to do to be able to concretize the builtin witnesses in SIL for optimization purposes, but the above should get something working.

-Joe

···

On Nov 28, 2017, at 8:33 PM, Tony Allevato <tony.allevato@gmail.com> wrote:

On Tue, Nov 28, 2017 at 11:23 AM Kelvin Ma via swift-evolution <swift-evolution@swift.org> wrote:
On Tue, Nov 28, 2017 at 12:59 PM, Joe Groff via swift-evolution <swift-evolution@swift.org> wrote:

> On Nov 28, 2017, at 10:52 AM, Vladimir.S <svabox@gmail.com> wrote:
>
> On 27.11.2017 20:28, Joe Groff via swift-evolution wrote:
>>> On Nov 20, 2017, at 5:43 PM, Chris Lattner via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>>>
>>>
>>>> On Nov 20, 2017, at 5:39 PM, Kelvin Ma via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>>>>
>>>> when SE-185 <https://github.com/apple/swift-evolution/blob/master/proposals/0185-synthesize-equatable-hashable.md> went through swift evolution, it was agreed that the next logical step <https://www.mail-archive.com/swift-evolution@swift.org/msg26162.html> is synthesizing these conformances for tuple types, though it was left out of the original proposal to avoid mission creep. I think now is the time to start thinking about this. i’m also tacking on Comparable to the other two protocols because there is precedent in the language from SE-15 <https://github.com/apple/swift-evolution/blob/master/proposals/0015-tuple-comparison-operators.md> that tuple comparison is something that makes sense to write.
>>>>
>>>> EHC conformance is even more important for tuples than it is for structs because tuples effectively have no workaround whereas in structs, you could just manually implement the conformance.
>>>
>>> In my opinion, you’re approaching this from the wrong direction. The fundamental problem here is that tuples can’t conform to a protocol. If they could, synthesizing these conformances would be straight-forward.
>> It would be a tractable intermediate problem to introduce built-in conformances for tuples (and perhaps metatypes) to Equatable/Hashable/Comparable without breaching the more general topic of allowing these types to have general protocol conformances. I think that would cover the highest-value use cases.
>
> So, shouldn't we do this first step ASAP and then design a good common solution to allow tuples/metatypes/funcs to confirm to custom protocols in some next version of Swift?
> I really believe this is the good practical decision and will be supported by community if such proposal will be on the table.
> Is there any drawback in such step?

The expected behavior of tuple Equatable/Hashable/Comparable seems obvious to me (though I could well be missing something), and any behavior we hardcode should be naturally replaceable by a generalized conformance mechanism, so it's primarily a "small matter of implementation". There would be some implementation cost to managing the special case in the compiler and runtime; the tradeoff seems worth it to me in this case, but others might reasonably disagree. Not speaking for the entire core team, I would personally support considering a proposal and implementation for builtin tuple Equatable/Hashable/Comparable conformance.

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

i wouldn’t know how to implement this but i could write up this proposal in a few days

I've been looking the past couple days at how to generalize the protocol conformance machinery to support structural types (even if we don't support arbitrary conformance syntactically, at least being able to hardcode the ones we want to synthesize initially). My free time isn't exactly plentiful, but I'm hoping to make some decent progress, so I'm happy to help where I can on this since it's a natural follow-up to my other Equatable/Hashable work!