Variadic generics discussion

I have a proposal for #6 in the pipe, but there are actually some
subtleties I have to work out (it's not as simple as just slapping a
generic type signature on a let constant).

I think #5 is just considered a 'bug' and doesn't need a proposal (it might
actually be finished already; I saw some commits recently); same with #4.
#7 is not very useful without variadic generics (it pretty much exists to
allow tuples to conform to protocols, and tuples are inherently variadic).

I wanted to take a stab at #2. The core team has talked so much about #1
that I'd be surprised if they don't already have an idea as to how they
want to do it, plus it's complicated for a number of reasons to get right.
In such a case having the community push forward an alternate proposal
would just be giving everyone more unneeded work.

#3 seems semantically straightforward. AFAIK there's nothing a subscript
can do that a getter and setter method can't do together, and methods can
already be generic. A proposal shouldn't be hard to put together.

Let me know your thoughts.

Best,
Austin

Ā·Ā·Ā·

On Tue, May 31, 2016 at 1:16 PM, Matthew Johnson <matthew@anandabits.com> wrote:

On May 31, 2016, at 2:56 PM, Austin Zheng via swift-evolution < > swift-evolution@swift.org> wrote:

This is pretty much where my thinking about the topic has led me as well.
I'll resign this topic to pursue some other, hopefully more relevant work,
although anyone who wants to continue the discussion is welcome to.

Seems reasonable to wait until we can at least evaluate the macro approach
properly.

Are you planning to continue work on generics? FWIW, my top priority list
for items without proposals is roughly:

1. Conditional conformance (
https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#conditional-conformances-
)
2. Parameterized extensions (
https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#parameterized-extensions
)
3. Generic subscripts (
https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#generic-subscripts
)
4. Recursive protocol constraints (
https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#nested-generics
)
5. Nested generics (
https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#nested-generics
)
6. Default generic arguments (
https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#default-generic-arguments
)
7. Extensions of structural types (
https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#extensions-of-structural-types
)

And this one seems like low hanging fruit:

Default implementations in protocols (
https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#default-implementations-in-protocols-
)

How does this compare to your priorities for generics?

On Tue, May 31, 2016 at 12:49 PM, Chris Lattner <clattner@apple.com> > wrote:

On May 31, 2016, at 12:17 PM, L Mihalkovic via swift-evolution < >> swift-evolution@swift.org> wrote:

well there is no macro system, and for the moment a clear statement from
chris that this is not on the table in the short term. the code in the
example looked like run-of-the-mill swift, except for the ā€œā€¦". so that
leaves us with swift looking code that would be executed by the compiler,
but with nothing particular to tell which parts to and which not. just a
thought.

Lets be clear though: variadic generics are not in scope for Swift 3
either.

I definitely donā€™t speak for the rest of the core team, nor have I
discussed it with themā€¦ but IMO, this whole feature seems like a better
fit for a macro system than it does to complicate the generics system.
Unlike C++ā€™s template system, our generics system inherently has runtime /
dynamic dispatch properties, and I donā€™t think that shoehorning variadics
into it is going to work out well.

-Chris

On May 31, 2016, at 7:59 PM, Austin Zheng <austinzheng@gmail.com> wrote:

How so? I'm interested in anything that can get us away from having to
generating code at compile-time.

On Tue, May 31, 2016 at 10:04 AM, L. Mihalkovic < >> laurent.mihalkovic@gmail.com> wrote:

What's interesting about the code in the manifesto is that it looks very
much like "..." is a runtime construct, as opposed to trying the get the
compiler to do the heavy lifting.

_______________________________________________
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

(I should mention that this is all just my personal read on the situation,
and shouldn't be construed as trying to stop or induce anyone else from
doing anything. Would love to see other proposals on generics, if people
want to work on them.)

Ā·Ā·Ā·

On Tue, May 31, 2016 at 1:25 PM, Austin Zheng <austinzheng@gmail.com> wrote:

I have a proposal for #6 in the pipe, but there are actually some
subtleties I have to work out (it's not as simple as just slapping a
generic type signature on a let constant).

I think #5 is just considered a 'bug' and doesn't need a proposal (it
might actually be finished already; I saw some commits recently); same with
#4. #7 is not very useful without variadic generics (it pretty much exists
to allow tuples to conform to protocols, and tuples are inherently
variadic).

I wanted to take a stab at #2. The core team has talked so much about #1
that I'd be surprised if they don't already have an idea as to how they
want to do it, plus it's complicated for a number of reasons to get right.
In such a case having the community push forward an alternate proposal
would just be giving everyone more unneeded work.

#3 seems semantically straightforward. AFAIK there's nothing a subscript
can do that a getter and setter method can't do together, and methods can
already be generic. A proposal shouldn't be hard to put together.

Let me know your thoughts.

Best,
Austin

On Tue, May 31, 2016 at 1:16 PM, Matthew Johnson <matthew@anandabits.com> > wrote:

On May 31, 2016, at 2:56 PM, Austin Zheng via swift-evolution < >> swift-evolution@swift.org> wrote:

This is pretty much where my thinking about the topic has led me as well.
I'll resign this topic to pursue some other, hopefully more relevant work,
although anyone who wants to continue the discussion is welcome to.

Seems reasonable to wait until we can at least evaluate the macro
approach properly.

Are you planning to continue work on generics? FWIW, my top priority
list for items without proposals is roughly:

1. Conditional conformance (
https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#conditional-conformances-
)
2. Parameterized extensions (
https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#parameterized-extensions
)
3. Generic subscripts (
https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#generic-subscripts
)
4. Recursive protocol constraints (
https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#nested-generics
)
5. Nested generics (
https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#nested-generics
)
6. Default generic arguments (
https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#default-generic-arguments
)
7. Extensions of structural types (
https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#extensions-of-structural-types
)

And this one seems like low hanging fruit:

Default implementations in protocols (
https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#default-implementations-in-protocols-
)

How does this compare to your priorities for generics?

On Tue, May 31, 2016 at 12:49 PM, Chris Lattner <clattner@apple.com> >> wrote:

On May 31, 2016, at 12:17 PM, L Mihalkovic via swift-evolution < >>> swift-evolution@swift.org> wrote:

well there is no macro system, and for the moment a clear statement from
chris that this is not on the table in the short term. the code in the
example looked like run-of-the-mill swift, except for the ā€œā€¦". so that
leaves us with swift looking code that would be executed by the compiler,
but with nothing particular to tell which parts to and which not. just a
thought.

Lets be clear though: variadic generics are not in scope for Swift 3
either.

I definitely donā€™t speak for the rest of the core team, nor have I
discussed it with themā€¦ but IMO, this whole feature seems like a better
fit for a macro system than it does to complicate the generics system.
Unlike C++ā€™s template system, our generics system inherently has runtime /
dynamic dispatch properties, and I donā€™t think that shoehorning variadics
into it is going to work out well.

-Chris

On May 31, 2016, at 7:59 PM, Austin Zheng <austinzheng@gmail.com> wrote:

How so? I'm interested in anything that can get us away from having to
generating code at compile-time.

On Tue, May 31, 2016 at 10:04 AM, L. Mihalkovic < >>> laurent.mihalkovic@gmail.com> wrote:

What's interesting about the code in the manifesto is that it looks
very much like "..." is a runtime construct, as opposed to trying the get
the compiler to do the heavy lifting.

_______________________________________________
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

(inline)

I have a proposal for #6 in the pipe, but there are actually some
subtleties I have to work out (it's not as simple as just slapping a
generic type signature on a let constant).

Cool. Looking forward to reviewing a draft when itā€™s ready.

I think #5 is just considered a 'bug' and doesn't need a proposal (it
might actually be finished already; I saw some commits recently); same with
#4. #7 is not very useful without variadic generics (it pretty much exists
to allow tuples to conform to protocols, and tuples are inherently
variadic).

Good to know 4 and 5 are considered bugs. I know #4 is important for the
standard library so I suppose that will ensure it is a priority soon enough.

I included #7 because it would still be nice to have for a number of
reasons. Maybe there is a way to pull it off for a handful of types that
are known to the compiler.

I wanted to take a stab at #2.

Are you still thinking about this one or did you decide not to pursue it?

I think I'd like to try writing something up.

The core team has talked so much about #1 that I'd be surprised if they
don't already have an idea as to how they want to do it, plus it's
complicated for a number of reasons to get right. In such a case having the
community push forward an alternate proposal would just be giving everyone
more unneeded work.

Agree here as well. Iā€™ve avoided generics proposals mostly because I
thought the core team was leading the charge on all them. It now appears
like that may not have been the right assumption across the board. I wish
we had a bit more visibility on this...

Yes, same. I'm going off this bullet point at the beginning of the generics
manifesto:

"I hope to achieve several things: ... Engage more of the community in
discussions of specific generics features, so we can coalesce around
designs for public review. And maybe even get some of them implemented."

#3 seems semantically straightforward. AFAIK there's nothing a subscript
can do that a getter and setter method can't do together, and methods can
already be generic. A proposal shouldn't be hard to put together.

Agree. Someone just needs to jump in and write it up. :-) If it had a
chance of making it into Swift 3 I would do it right away, but itā€™s hard to
tell...

I'd be happy to write up a proposal, especially if it's as straightforward
as it seems.

Ā·Ā·Ā·

On Tue, May 31, 2016 at 1:34 PM, Matthew Johnson <matthew@anandabits.com> wrote:

On May 31, 2016, at 3:25 PM, Austin Zheng <austinzheng@gmail.com> wrote:

This is pretty much where my thinking about the topic has led me as well. I'll resign this topic to pursue some other, hopefully more relevant work, although anyone who wants to continue the discussion is welcome to.

Seems reasonable to wait until we can at least evaluate the macro approach properly.

Are you planning to continue work on generics? FWIW, my top priority list for items without proposals is roughly:

1. Conditional conformance (https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#conditional-conformances-\)
2. Parameterized extensions (https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#parameterized-extensions\)
3. Generic subscripts (https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#generic-subscripts\)
4. Recursive protocol constraints (https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#nested-generics\)
5. Nested generics (https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#nested-generics\)
6. Default generic arguments (https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#default-generic-arguments\)
7. Extensions of structural types (https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#extensions-of-structural-types\)

And this one seems like low hanging fruit:

Default implementations in protocols (https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#default-implementations-in-protocols-\)

How does this compare to your priorities for generics?

Ā·Ā·Ā·

On May 31, 2016, at 2:56 PM, Austin Zheng via swift-evolution <swift-evolution@swift.org> wrote:

On Tue, May 31, 2016 at 12:49 PM, Chris Lattner <clattner@apple.com <mailto:clattner@apple.com>> wrote:

On May 31, 2016, at 12:17 PM, L Mihalkovic via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

well there is no macro system, and for the moment a clear statement from chris that this is not on the table in the short term. the code in the example looked like run-of-the-mill swift, except for the ā€œā€¦". so that leaves us with swift looking code that would be executed by the compiler, but with nothing particular to tell which parts to and which not. just a thought.

Lets be clear though: variadic generics are not in scope for Swift 3 either.

I definitely donā€™t speak for the rest of the core team, nor have I discussed it with themā€¦ but IMO, this whole feature seems like a better fit for a macro system than it does to complicate the generics system. Unlike C++ā€™s template system, our generics system inherently has runtime / dynamic dispatch properties, and I donā€™t think that shoehorning variadics into it is going to work out well.

-Chris

On May 31, 2016, at 7:59 PM, Austin Zheng <austinzheng@gmail.com <mailto:austinzheng@gmail.com>> wrote:

How so? I'm interested in anything that can get us away from having to generating code at compile-time.

On Tue, May 31, 2016 at 10:04 AM, L. Mihalkovic <laurent.mihalkovic@gmail.com <mailto:laurent.mihalkovic@gmail.com>> wrote:

What's interesting about the code in the manifesto is that it looks very much like "..." is a runtime construct, as opposed to trying the get the compiler to do the heavy lifting.

_______________________________________________
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

I have a proposal for #6 in the pipe, but there are actually some subtleties I have to work out (it's not as simple as just slapping a generic type signature on a let constant).

Cool. Looking forward to reviewing a draft when itā€™s ready.

I think #5 is just considered a 'bug' and doesn't need a proposal (it might actually be finished already; I saw some commits recently); same with #4. #7 is not very useful without variadic generics (it pretty much exists to allow tuples to conform to protocols, and tuples are inherently variadic).

Good to know 4 and 5 are considered bugs. I know #4 is important for the standard library so I suppose that will ensure it is a priority soon enough.

I included #7 because it would still be nice to have for a number of reasons. Maybe there is a way to pull it off for a handful of types that are known to the compiler.

I wanted to take a stab at #2.

Are you still thinking about this one or did you decide not to pursue it?

The core team has talked so much about #1 that I'd be surprised if they don't already have an idea as to how they want to do it, plus it's complicated for a number of reasons to get right. In such a case having the community push forward an alternate proposal would just be giving everyone more unneeded work.

Agree here as well. Iā€™ve avoided generics proposals mostly because I thought the core team was leading the charge on all them. It now appears like that may not have been the right assumption across the board. I wish we had a bit more visibility on this...

#3 seems semantically straightforward. AFAIK there's nothing a subscript can do that a getter and setter method can't do together, and methods can already be generic. A proposal shouldn't be hard to put together.

Agree. Someone just needs to jump in and write it up. :-) If it had a chance of making it into Swift 3 I would do it right away, but itā€™s hard to tell...

Ā·Ā·Ā·

On May 31, 2016, at 3:25 PM, Austin Zheng <austinzheng@gmail.com> wrote:

Let me know your thoughts.

Best,
Austin

On Tue, May 31, 2016 at 1:16 PM, Matthew Johnson <matthew@anandabits.com <mailto:matthew@anandabits.com>> wrote:

On May 31, 2016, at 2:56 PM, Austin Zheng via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

This is pretty much where my thinking about the topic has led me as well. I'll resign this topic to pursue some other, hopefully more relevant work, although anyone who wants to continue the discussion is welcome to.

Seems reasonable to wait until we can at least evaluate the macro approach properly.

Are you planning to continue work on generics? FWIW, my top priority list for items without proposals is roughly:

1. Conditional conformance (https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#conditional-conformances-\)
2. Parameterized extensions (https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#parameterized-extensions\)
3. Generic subscripts (https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#generic-subscripts\)
4. Recursive protocol constraints (https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#nested-generics\)
5. Nested generics (https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#nested-generics\)
6. Default generic arguments (https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#default-generic-arguments\)
7. Extensions of structural types (https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#extensions-of-structural-types\)

And this one seems like low hanging fruit:

Default implementations in protocols (https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#default-implementations-in-protocols-\)

How does this compare to your priorities for generics?

On Tue, May 31, 2016 at 12:49 PM, Chris Lattner <clattner@apple.com <mailto:clattner@apple.com>> wrote:

On May 31, 2016, at 12:17 PM, L Mihalkovic via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

well there is no macro system, and for the moment a clear statement from chris that this is not on the table in the short term. the code in the example looked like run-of-the-mill swift, except for the ā€œā€¦". so that leaves us with swift looking code that would be executed by the compiler, but with nothing particular to tell which parts to and which not. just a thought.

Lets be clear though: variadic generics are not in scope for Swift 3 either.

I definitely donā€™t speak for the rest of the core team, nor have I discussed it with themā€¦ but IMO, this whole feature seems like a better fit for a macro system than it does to complicate the generics system. Unlike C++ā€™s template system, our generics system inherently has runtime / dynamic dispatch properties, and I donā€™t think that shoehorning variadics into it is going to work out well.

-Chris

On May 31, 2016, at 7:59 PM, Austin Zheng <austinzheng@gmail.com <mailto:austinzheng@gmail.com>> wrote:

How so? I'm interested in anything that can get us away from having to generating code at compile-time.

On Tue, May 31, 2016 at 10:04 AM, L. Mihalkovic <laurent.mihalkovic@gmail.com <mailto:laurent.mihalkovic@gmail.com>> wrote:

What's interesting about the code in the manifesto is that it looks very much like "..." is a runtime construct, as opposed to trying the get the compiler to do the heavy lifting.

_______________________________________________
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

Cool! Iā€™ll continue to play the role of providing as much feedback as I canā€¦ :-)

Ā·Ā·Ā·

On May 31, 2016, at 3:39 PM, Austin Zheng <austinzheng@gmail.com> wrote:

(inline)

On Tue, May 31, 2016 at 1:34 PM, Matthew Johnson <matthew@anandabits.com <mailto:matthew@anandabits.com>> wrote:

On May 31, 2016, at 3:25 PM, Austin Zheng <austinzheng@gmail.com <mailto:austinzheng@gmail.com>> wrote:

I have a proposal for #6 in the pipe, but there are actually some subtleties I have to work out (it's not as simple as just slapping a generic type signature on a let constant).

Cool. Looking forward to reviewing a draft when itā€™s ready.

I think #5 is just considered a 'bug' and doesn't need a proposal (it might actually be finished already; I saw some commits recently); same with #4. #7 is not very useful without variadic generics (it pretty much exists to allow tuples to conform to protocols, and tuples are inherently variadic).

Good to know 4 and 5 are considered bugs. I know #4 is important for the standard library so I suppose that will ensure it is a priority soon enough.

I included #7 because it would still be nice to have for a number of reasons. Maybe there is a way to pull it off for a handful of types that are known to the compiler.

I wanted to take a stab at #2.

Are you still thinking about this one or did you decide not to pursue it?

I think I'd like to try writing something up.

The core team has talked so much about #1 that I'd be surprised if they don't already have an idea as to how they want to do it, plus it's complicated for a number of reasons to get right. In such a case having the community push forward an alternate proposal would just be giving everyone more unneeded work.

Agree here as well. Iā€™ve avoided generics proposals mostly because I thought the core team was leading the charge on all them. It now appears like that may not have been the right assumption across the board. I wish we had a bit more visibility on this...

Yes, same. I'm going off this bullet point at the beginning of the generics manifesto:

"I hope to achieve several things: ... Engage more of the community in discussions of specific generics features, so we can coalesce around designs for public review. And maybe even get some of them implemented."

#3 seems semantically straightforward. AFAIK there's nothing a subscript can do that a getter and setter method can't do together, and methods can already be generic. A proposal shouldn't be hard to put together.

Agree. Someone just needs to jump in and write it up. :-) If it had a chance of making it into Swift 3 I would do it right away, but itā€™s hard to tell...

I'd be happy to write up a proposal, especially if it's as straightforward as it seems.

There's definitely the possibility of going off the deep end with complexity like C++, but since we already have tuples as a primitive language feature, I think there's a straightforward language design that enables the most important use cases for variadics. If we have "tuple splatting" for argument forwarding, and some support for iterating tuples, like we briefly discussed in the context of (4 x Int) fixed-sized homogeneous tuples, that'd probably be enough.

-Joe

Ā·Ā·Ā·

On May 31, 2016, at 12:49 PM, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

On May 31, 2016, at 12:17 PM, L Mihalkovic via swift-evolution <swift-evolution@swift.org> wrote:

well there is no macro system, and for the moment a clear statement from chris that this is not on the table in the short term. the code in the example looked like run-of-the-mill swift, except for the ā€œā€¦". so that leaves us with swift looking code that would be executed by the compiler, but with nothing particular to tell which parts to and which not. just a thought.

Lets be clear though: variadic generics are not in scope for Swift 3 either.

I definitely donā€™t speak for the rest of the core team, nor have I discussed it with themā€¦ but IMO, this whole feature seems like a better fit for a macro system than it does to complicate the generics system. Unlike C++ā€™s template system, our generics system inherently has runtime / dynamic dispatch properties, and I donā€™t think that shoehorning variadics into it is going to work out well.

This is very close to my priority list. That said, I think that all of these are out of scope for swift 3 sadly.

After Swift 3, the priority list will be driven by what the standard library needs to get its APIs realized in their ideal form (eg without any of the _ protocol hacks). Conditional conformances certainly top the list, but we will have to carefully and ruthlessly prioritize things in order to get to ABI stability.

-Chris

Ā·Ā·Ā·

On May 31, 2016, at 2:16 PM, Matthew Johnson <matthew@anandabits.com> wrote:

On May 31, 2016, at 2:56 PM, Austin Zheng via swift-evolution <swift-evolution@swift.org> wrote:

This is pretty much where my thinking about the topic has led me as well. I'll resign this topic to pursue some other, hopefully more relevant work, although anyone who wants to continue the discussion is welcome to.

Seems reasonable to wait until we can at least evaluate the macro approach properly.

Are you planning to continue work on generics? FWIW, my top priority list for items without proposals is roughly:

1. Conditional conformance (https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#conditional-conformances-\)
2. Parameterized extensions (https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#parameterized-extensions\)
3. Generic subscripts (https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#generic-subscripts\)
4. Recursive protocol constraints (https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#nested-generics\)
5. Nested generics (https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#nested-generics\)
6. Default generic arguments (https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#default-generic-arguments\)
7. Extensions of structural types (https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#extensions-of-structural-types\)

And this one seems like low hanging fruit:

Default implementations in protocols (https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#default-implementations-in-protocols-\)

How does this compare to your priorities for generics?

On Tue, May 31, 2016 at 12:49 PM, Chris Lattner <clattner@apple.com> wrote:

On May 31, 2016, at 12:17 PM, L Mihalkovic via swift-evolution <swift-evolution@swift.org> wrote:

well there is no macro system, and for the moment a clear statement from chris that this is not on the table in the short term. the code in the example looked like run-of-the-mill swift, except for the ā€œā€¦". so that leaves us with swift looking code that would be executed by the compiler, but with nothing particular to tell which parts to and which not. just a thought.

Lets be clear though: variadic generics are not in scope for Swift 3 either.

I definitely donā€™t speak for the rest of the core team, nor have I discussed it with themā€¦ but IMO, this whole feature seems like a better fit for a macro system than it does to complicate the generics system. Unlike C++ā€™s template system, our generics system inherently has runtime / dynamic dispatch properties, and I donā€™t think that shoehorning variadics into it is going to work out well.

-Chris

On May 31, 2016, at 7:59 PM, Austin Zheng <austinzheng@gmail.com> wrote:

How so? I'm interested in anything that can get us away from having to generating code at compile-time.

On Tue, May 31, 2016 at 10:04 AM, L. Mihalkovic <laurent.mihalkovic@gmail.com> wrote:

What's interesting about the code in the manifesto is that it looks very much like "..." is a runtime construct, as opposed to trying the get the compiler to do the heavy lifting.

_______________________________________________
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

There's definitely the possibility of going off the deep end with complexity like C++, but since we already have tuples as a primitive language feature, I think there's a straightforward language design that enables the most important use cases for variadics. If we have "tuple splatting" for argument forwarding, and some support for iterating tuples, like we briefly discussed in the context of (4 x Int) fixed-sized homogeneous tuples, that'd probably be enough.

I read the original proposal, started writing up a response along these lines, and then scrolled up to see what others had said. I'm glad you agree!

Here's my sketch.

* * *

In general, my preferred direction for this feature would tie variadics closely to tuples, and variadic types closely to tuple types. To wit:

1. We should dust off the old tuple indexing proposal (I actually forgot it was never reviewed) and get it through, along with tuple `count`, `map`, and probably a few other Collection-like operations which generate fixed signatures. (I'm going to use a method-style syntax, but a #function-style syntax would work too; we could even introduce a .#method-style syntax.)

  let tuple: (Int, Int, Int, Int) = (2, 4, 6, 8)
  print(tuple[tuple.0]) // => 6
  print(tuple.map { $0 / 2 }) // => (1, 2, 3, 4)

2. We should allow you to use analogous operators on the type of a tuple, too.

  let value: (Int, String)[1] = "Hello, world!"
  (Int, String).map { $0.Type } // => (Int.Type, String.Type)

3. We should change our existing variadic parameters to create tuples, not Arrays.

  func print(_ items: (Any...), separator: String = "", terminator: String = "\n") {
    items.0 // Yes, that's a thing you can do

4. We should add a splat operator which unpacks tuples into (possibly variadic) parameters.

  print(tuple...)

5. We should allow you to define variadic type parameters.

  // Note: If you had written `items: Items` instead of `items: Items...`, it would've taken a tuple
  // of various LocalizedStringConvertible types.
  func localizedPrint<Items: (LocalizedStringConvertible...)>(_ items: Items..., separator: String = "", terminator: String = "\n") {
    print(items.map { $0.localizedDescription }, separator: separator, terminator: terminator)
  }

6. We should extend splat to unpack tuple types into (possibly variadic) type parameters.

  typealias Pair = (String, Int)
  let table: Dictionary<Pair...> = [:]

(7. Optional pet-peeve fixer, which I will not actually demonstrate: Require unconstrained type parameters to be spelled `T: Any`, not just `T`. This will remove an asymmetry, in that a variable-length tuple of any type has to be spelled `T: (Any...)`, but a single parameter is just spelled `T`.)

What do we end up with here?

Zip:

  struct ZipSequence<Sequences: (Sequence...)>: Sequence {
    typealias Iterator: ZipIterator<Sequences.map { $0.Iterator }...>
    
    var sequences: Sequences
    
    func makeIterator() -> ZipIterator<Sequences...> {
      return ZipIterator.init(sequences.map { $0.makeIterator() }...)
    }
    
    init(_ sequences: Sequences...) {
      self.sequences = sequences
    }
  }
  
  struct ZipIterator<Iterators: (IteratorProtocol...)>: IteratorProtocol {
    typealias Element = Iterators.map { $0.Element }
    
    var iterators: Iterators
    
    init(_ iterators: Iterators...) {
      self.iterators = iterators
    }
    
    mutating func next() -> Element? {
      // Note: It may be too difficult to assign a type to this reduction;
      // something like the proposal's `#invert` may thus be necessary.
      // If it is added, I would hope that an analogous operation would
      // be added to `Sequence`s of `Optional`s.
      let nextValues = iterators.map { $0.next() }.reduce(Optional( () )) { earlier, this in
        guard let earlier = earlier, this = this else {
          return nil
        }
        return earlier + (this)
      }
      guard let nextValues = nextValues else {
        return nil
      }
      return nextValues
    }
  }

Function application is basically just a use of the splat feature:

  // Note that the `args: Args` here is *not* `...`ed, so it takes a tuple.
  // Meanwhile, the `Args` in `(Args...) -> Result` does have `...`, so it's looking
  // for arguments which that tuple could be splatted into.
  func apply<Args: (Any...), Return>(_ args: Args, to function: (Args...) -> Return) -> Return {
    return function(args...)
  }
  
  func method<Instance, Args: (Args...), Return>(_ name: String, on instance: Instance) -> ((Args...) -> Return)? {
    ...
  }

MultiMap:

  func multiMap<Sequences: (Sequence...), Return>(_ sequences: (Sequences...), transform: (Sequences.map { $0.Iterator.Element }...) -> Return) -> [Return] {
    var returns: [Return] =
    
    // You could do this by manually making iterators, but why bother when we already have the right abstraction?
    for elems in zip(sequences...) {
      returns.append(transform(elems...))
    }
    
    return returns
  }

Advantages of this approach, as I see them:

* Variadics are entirely a creature of parameter lists and type parameter lists; outside of those, they are always represented as a tuple. That means, for instance, that there is no need for variadics to reach into places like variables.

* `...` goes in exactly two places: After a type name within the definition of a tuple type, and after an expression being splatted into a parameter list. There's no proliferation of dots throughout the language or confusing leading-vs.-trailing dots thing.

* Many of these features are useful in non-variadic code. For instance, Collection-like tuples are a feature people want already.

* We stick closer to already-implemented features, rather than inventing a whole lot of completely novel stuff, like `#rest` and `#fold` and `#vector`.

Disadvantages:

* This leans rather heavily on tuple and tuple type features which will probably, at least for now, have to be built into the compiler. (You might be able to make them macros later.)

* This _may_ raise the grim specter of 1-tuples, but I'm not sure about that. (Perhaps even the concrete-tuple members should be hashed, like `#count` and `#map`? That would allow them to be applied to single values.)

Ā·Ā·Ā·

--
Brent Royal-Gordon
Architechies

I agree that this is a better design for Swift than the monstrosity I
started out with.

The "biggest" technical challenge I see is being able to type a reduction
sort of operator on a heterogenous tuple based on on whatever protocols and
constraints are common to its constituent members. For example:

// Every Tn in T... is Fooable and Barrable
let x : (T...)
reduce(x, reducer, startingValue)

func reducer<X : ???>(startingValue: U, eachMemberOfT: X) -> U { ... }

How do we bound ??? such that 'reducer' is useful while still being
statically type sound? Honestly, that's the most interesting question to
me. Generalized existentials might help with that.

Other questions (inherent to any proposal) would be:

- How do we resolve the impedance mismatch between tuples and function
argument lists? Is it even worth trying to resolve this mismatch, given
that argument lists are intentionally not intended to mirror tuples?

- As you said, how do variadic generics work in the 0- and 1-member cases?

I definitely agree that tuples are a inherently variadic, inherently
generic, sufficiently primitive data structure to map well onto the concept.

Austin

Ā·Ā·Ā·

On Tue, May 31, 2016 at 6:29 PM, Brent Royal-Gordon via swift-evolution < swift-evolution@swift.org> wrote:

> There's definitely the possibility of going off the deep end with
complexity like C++, but since we already have tuples as a primitive
language feature, I think there's a straightforward language design that
enables the most important use cases for variadics. If we have "tuple
splatting" for argument forwarding, and some support for iterating tuples,
like we briefly discussed in the context of (4 x Int) fixed-sized
homogeneous tuples, that'd probably be enough.

I read the original proposal, started writing up a response along these
lines, and then scrolled up to see what others had said. I'm glad you agree!

Here's my sketch.

* * *

In general, my preferred direction for this feature would tie variadics
closely to tuples, and variadic types closely to tuple types. To wit:

1. We should dust off the old tuple indexing proposal (I actually forgot
it was never reviewed) and get it through, along with tuple `count`, `map`,
and probably a few other Collection-like operations which generate fixed
signatures. (I'm going to use a method-style syntax, but a #function-style
syntax would work too; we could even introduce a .#method-style syntax.)

        let tuple: (Int, Int, Int, Int) = (2, 4, 6, 8)
        print(tuple[tuple.0]) // => 6
        print(tuple.map { $0 / 2 }) // => (1, 2, 3, 4)

2. We should allow you to use analogous operators on the type of a tuple,
too.

        let value: (Int, String)[1] = "Hello, world!"
        (Int, String).map { $0.Type } // => (Int.Type,
String.Type)

3. We should change our existing variadic parameters to create tuples, not
Arrays.

        func print(_ items: (Any...), separator: String = "", terminator:
String = "\n") {
                items.0 // Yes, that's a thing you can do

4. We should add a splat operator which unpacks tuples into (possibly
variadic) parameters.

        print(tuple...)

5. We should allow you to define variadic type parameters.

        // Note: If you had written `items: Items` instead of `items:
Items...`, it would've taken a tuple
        // of various LocalizedStringConvertible types.
        func localizedPrint<Items: (LocalizedStringConvertible...)>(_
items: Items..., separator: String = "", terminator: String = "\n") {
                print(items.map { $0.localizedDescription }, separator:
separator, terminator: terminator)
        }

6. We should extend splat to unpack tuple types into (possibly variadic)
type parameters.

        typealias Pair = (String, Int)
        let table: Dictionary<Pair...> = [:]

(7. Optional pet-peeve fixer, which I will not actually demonstrate:
Require unconstrained type parameters to be spelled `T: Any`, not just `T`.
This will remove an asymmetry, in that a variable-length tuple of any type
has to be spelled `T: (Any...)`, but a single parameter is just spelled
`T`.)

What do we end up with here?

Zip:

        struct ZipSequence<Sequences: (Sequence...)>: Sequence {
                typealias Iterator: ZipIterator<Sequences.map {
$0.Iterator }...>

                var sequences: Sequences

                func makeIterator() -> ZipIterator<Sequences...> {
                        return ZipIterator.init(sequences.map {
$0.makeIterator() }...)
                }

                init(_ sequences: Sequences...) {
                        self.sequences = sequences
                }
        }

        struct ZipIterator<Iterators: (IteratorProtocol...)>:
IteratorProtocol {
                typealias Element = Iterators.map { $0.Element }

                var iterators: Iterators

                init(_ iterators: Iterators...) {
                        self.iterators = iterators
                }

                mutating func next() -> Element? {
                        // Note: It may be too difficult to assign a type
to this reduction;
                        // something like the proposal's `#invert` may
thus be necessary.
                        // If it is added, I would hope that an analogous
operation would
                        // be added to `Sequence`s of `Optional`s.
                        let nextValues = iterators.map { $0.next()
}.reduce(Optional( () )) { earlier, this in
                                guard let earlier = earlier, this = this
else {
                                        return nil
                                }
                                return earlier + (this)
                        }
                        guard let nextValues = nextValues else {
                                return nil
                        }
                        return nextValues
                }
        }

Function application is basically just a use of the splat feature:

        // Note that the `args: Args` here is *not* `...`ed, so it takes a
tuple.
        // Meanwhile, the `Args` in `(Args...) -> Result` does have `...`,
so it's looking
        // for arguments which that tuple could be splatted into.
        func apply<Args: (Any...), Return>(_ args: Args, to function:
(Args...) -> Return) -> Return {
                return function(args...)
        }

        func method<Instance, Args: (Args...), Return>(_ name: String, on
instance: Instance) -> ((Args...) -> Return)? {
                ...
        }

MultiMap:

        func multiMap<Sequences: (Sequence...), Return>(_ sequences:
(Sequences...), transform: (Sequences.map { $0.Iterator.Element }...) ->
Return) -> [Return] {
                var returns: [Return] =

                // You could do this by manually making iterators, but why
bother when we already have the right abstraction?
                for elems in zip(sequences...) {
                        returns.append(transform(elems...))
                }

                return returns
        }

Advantages of this approach, as I see them:

* Variadics are entirely a creature of parameter lists and type parameter
lists; outside of those, they are always represented as a tuple. That
means, for instance, that there is no need for variadics to reach into
places like variables.

* `...` goes in exactly two places: After a type name within the
definition of a tuple type, and after an expression being splatted into a
parameter list. There's no proliferation of dots throughout the language or
confusing leading-vs.-trailing dots thing.

* Many of these features are useful in non-variadic code. For instance,
Collection-like tuples are a feature people want already.

* We stick closer to already-implemented features, rather than inventing a
whole lot of completely novel stuff, like `#rest` and `#fold` and `#vector`.

Disadvantages:

* This leans rather heavily on tuple and tuple type features which will
probably, at least for now, have to be built into the compiler. (You might
be able to make them macros later.)

* This _may_ raise the grim specter of 1-tuples, but I'm not sure about
that. (Perhaps even the concrete-tuple members should be hashed, like
`#count` and `#map`? That would allow them to be applied to single values.)

--
Brent Royal-Gordon
Architechies

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

Ok, fair enough. However, I think that it is inescapable that any discussion of variadic generics needs to include implementation concerns.

-Chris

Ā·Ā·Ā·

On May 31, 2016, at 6:05 PM, Joe Groff <jgroff@apple.com> wrote:

On May 31, 2016, at 12:49 PM, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

On May 31, 2016, at 12:17 PM, L Mihalkovic via swift-evolution <swift-evolution@swift.org> wrote:

well there is no macro system, and for the moment a clear statement from chris that this is not on the table in the short term. the code in the example looked like run-of-the-mill swift, except for the ā€œā€¦". so that leaves us with swift looking code that would be executed by the compiler, but with nothing particular to tell which parts to and which not. just a thought.

Lets be clear though: variadic generics are not in scope for Swift 3 either.

I definitely donā€™t speak for the rest of the core team, nor have I discussed it with themā€¦ but IMO, this whole feature seems like a better fit for a macro system than it does to complicate the generics system. Unlike C++ā€™s template system, our generics system inherently has runtime / dynamic dispatch properties, and I donā€™t think that shoehorning variadics into it is going to work out well.

There's definitely the possibility of going off the deep end with complexity like C++, but since we already have tuples as a primitive language feature, I think there's a straightforward language design that enables the most important use cases for variadics. If we have "tuple splatting" for argument forwarding, and some support for iterating tuples, like we briefly discussed in the context of (4 x Int) fixed-sized homogeneous tuples, that'd probably be enough.

This is very close to my priority list. That said, I think that all of these are out of scope for swift 3 sadly.

Happy to hear these priorities look about right to you also. (I realized afterwards that I left off opening existentials which I would put around 5 or 6)

BTW, generalized existentials is #2 for me if we include things that already have proposals as well. That going to be a game changer.

I've already been assuming we won't see any major new generics features in Swift 3.

After Swift 3, the priority list will be driven by what the standard library needs to get its APIs realized in their ideal form (eg without any of the _ protocol hacks). Conditional conformances certainly top the list, but we will have to carefully and ruthlessly prioritize things in order to get to ABI stability.

Makes sense.

Ā·Ā·Ā·

Sent from my iPad

On May 31, 2016, at 7:10 PM, Chris Lattner <clattner@apple.com> wrote:

-Chris

On May 31, 2016, at 2:16 PM, Matthew Johnson <matthew@anandabits.com> wrote:

On May 31, 2016, at 2:56 PM, Austin Zheng via swift-evolution <swift-evolution@swift.org> wrote:

This is pretty much where my thinking about the topic has led me as well. I'll resign this topic to pursue some other, hopefully more relevant work, although anyone who wants to continue the discussion is welcome to.

Seems reasonable to wait until we can at least evaluate the macro approach properly.

Are you planning to continue work on generics? FWIW, my top priority list for items without proposals is roughly:

1. Conditional conformance (https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#conditional-conformances-\)
2. Parameterized extensions (https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#parameterized-extensions\)
3. Generic subscripts (https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#generic-subscripts\)
4. Recursive protocol constraints (https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#nested-generics\)
5. Nested generics (https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#nested-generics\)
6. Default generic arguments (https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#default-generic-arguments\)
7. Extensions of structural types (https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#extensions-of-structural-types\)

And this one seems like low hanging fruit:

Default implementations in protocols (https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#default-implementations-in-protocols-\)

How does this compare to your priorities for generics?

On Tue, May 31, 2016 at 12:49 PM, Chris Lattner <clattner@apple.com> wrote:

On May 31, 2016, at 12:17 PM, L Mihalkovic via swift-evolution <swift-evolution@swift.org> wrote:

well there is no macro system, and for the moment a clear statement from chris that this is not on the table in the short term. the code in the example looked like run-of-the-mill swift, except for the ā€œā€¦". so that leaves us with swift looking code that would be executed by the compiler, but with nothing particular to tell which parts to and which not. just a thought.

Lets be clear though: variadic generics are not in scope for Swift 3 either.

I definitely donā€™t speak for the rest of the core team, nor have I discussed it with themā€¦ but IMO, this whole feature seems like a better fit for a macro system than it does to complicate the generics system. Unlike C++ā€™s template system, our generics system inherently has runtime / dynamic dispatch properties, and I donā€™t think that shoehorning variadics into it is going to work out well.

-Chris

On May 31, 2016, at 7:59 PM, Austin Zheng <austinzheng@gmail.com> wrote:

How so? I'm interested in anything that can get us away from having to generating code at compile-time.

On Tue, May 31, 2016 at 10:04 AM, L. Mihalkovic <laurent.mihalkovic@gmail.com> wrote:

What's interesting about the code in the manifesto is that it looks very much like "..." is a runtime construct, as opposed to trying the get the compiler to do the heavy lifting.

_______________________________________________
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

I agree that this is a better design for Swift than the monstrosity I started out with.

The "biggest" technical challenge I see is being able to type a reduction sort of operator on a heterogenous tuple based on on whatever protocols and constraints are common to its constituent members. For example:

// Every Tn in T... is Fooable and Barrable
let x : (T...)
reduce(x, reducer, startingValue)

func reducer<X : ???>(startingValue: U, eachMemberOfT: X) -> U { ... }

How do we bound ??? such that 'reducer' is useful while still being statically type sound? Honestly, that's the most interesting question to me. Generalized existentials might help with that.

You know, I'm not a big fan of the `&` syntax people are pushing in the `Any<>` thread, but if you ignore the Ceylon people begging for union types, I think a sensible alternative meaning for `|` would be "all common supertypes of these types". Then you could write:

  // Bottom here is the bottom type: the subtype of all types.
  (Int, String, Bool).reduce(Bottom, combine: |)

And you'll end up with something like:

  Equatable & Hashable & _Reflectable

Which are the three protocols all of those types support. If they'd supported no common protocols, it would've ended up with `Any`. (Interestingly, this is arguably the same operation which should be used to determine the return value of tuple subscripting.)

Of course, nothing about having this feature *requires* that we use `&` and `|`; that was just the inspiration for it.

Other questions (inherent to any proposal) would be:

- How do we resolve the impedance mismatch between tuples and function argument lists? Is it even worth trying to resolve this mismatch, given that argument lists are intentionally not intended to mirror tuples?

As far as I know, tuples support a subset of argument list features. (For instance, they don't support default values.) So if you splat a tuple into a parameter list, the worst case is that you won't get to use features like those.

One mismatch is that tuples barely care about their argument labels, while parameter lists select overloads on them. My temptation would be to require you to disambiguate with `(x:y:z)` syntax if you were splatting in an unclear way.

  let triple = (0, 10, 2)
  
  stride(triple...) // Illegal due to ambiguity; write one of these:
  stride(from:to:by:)(triple...)
  stride(from:through:by:)(triple...)

One useful thing here is that the arity and types of a tuple are known at compile time, so we can figure out ahead of time how to interpret the call. That wouldn't be the case if you could splat arrays.

(Incidentally, we might want to offer a pseudo-failable initializer to create a tuple from a sequence:

  if let triple = (Int, Int, Int)(intArray) {
    return stride(from:to:by:)(triple...)
  }

That would indirectly allow you to splat the contents of an array into a parameter list.)

- As you said, how do variadic generics work in the 0- and 1-member cases?

I don't think 0-tuples are a big deal, except in that there's no good starting value for certain reductions. Adding a bottom type (as I did in the `reduce` example above) would fix that.

1-tuples are a bigger problem, because if you have a parameter like `(Any...)`, you can't afford to interpret `((Int, String))` as `(Int, String)`. It might be possible to support 1-tuples only in contexts where you're using a variadic tuple, but I'm kind of skeptical of that idea.

Personally, I wish we'd just acknowledge `(SomeType)` (or maybe `(SomeType, )`) as something different from `SomeType` and stop fretting. Sure, it's a semi-useless degenerate case, but so are one-case `enum`s and `Optional<Void>`s, and we don't ban those. Banning `T -> U` syntax has already removed one of the sources of ambiguity here.

Ā·Ā·Ā·

--
Brent Royal-Gordon
Architechies

well there is no macro system, and for the moment a clear statement from chris that this is not on the table in the short term. the code in the example looked like run-of-the-mill swift, except for the ā€œā€¦". so that leaves us with swift looking code that would be executed by the compiler, but with nothing particular to tell which parts to and which not. just a thought.

Lets be clear though: variadic generics are not in scope for Swift 3 either.

+1

I definitely donā€™t speak for the rest of the core team, nor have I discussed it with themā€¦ but IMO, this whole feature seems like a better fit for a

macro system

+++1

than it does to complicate the generics system. Unlike C++ā€™s template system, our generics system inherently has runtime / dynamic dispatch properties, and I donā€™t think that shoehorning variadics into it is going to work out well.

just for my education and purely as a thought experiment: couldnā€™t a purely runtime system based on some assistance from the compiler via a couple of synthesized ā€˜magicā€™ variables inside the scope of a function provide access to the types and the values as tuples? that would only give variadic generic functions, but that is something in itself. I would never claim the idea, but it looks close enough to what D is doing.

Ā·Ā·Ā·

On May 31, 2016, at 9:49 PM, Chris Lattner <clattner@apple.com> wrote:

On May 31, 2016, at 12:17 PM, L Mihalkovic via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

-Chris

On May 31, 2016, at 7:59 PM, Austin Zheng <austinzheng@gmail.com <mailto:austinzheng@gmail.com>> wrote:

How so? I'm interested in anything that can get us away from having to generating code at compile-time.

On Tue, May 31, 2016 at 10:04 AM, L. Mihalkovic <laurent.mihalkovic@gmail.com <mailto:laurent.mihalkovic@gmail.com>> wrote:

What's interesting about the code in the manifesto is that it looks very much like "..." is a runtime construct, as opposed to trying the get the compiler to do the heavy lifting.

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

I agree that this is a better design for Swift than the monstrosity I started out with.

The "biggest" technical challenge I see is being able to type a reduction sort of operator on a heterogenous tuple based on on whatever protocols and constraints are common to its constituent members. For example:

// Every Tn in T... is Fooable and Barrable
let x : (T...)
reduce(x, reducer, startingValue)

func reducer<X : ???>(startingValue: U, eachMemberOfT: X) -> U { ... }

How do we bound ??? such that 'reducer' is useful while still being statically type sound? Honestly, that's the most interesting question to me. Generalized existentials might help with that.

If every T is Fooable and Barrable, couldn't `eachMemberOfT` be (inout U, protocol<Fooable, Barrable>) -> ()?

Other questions (inherent to any proposal) would be:

- How do we resolve the impedance mismatch between tuples and function argument lists? Is it even worth trying to resolve this mismatch, given that argument lists are intentionally not intended to mirror tuples?

The impedance mismatch between function arguments and tuples is superficial. You ought to be able to splat and bind tuples into function arguments, e.g.:

  let args = (1, 2)
  foo(bar:bas:)(args...)

  func variadicFn<T: Runcible...>(_ args: T...) { ... }

- As you said, how do variadic generics work in the 0- and 1-member cases?

What problem are you referring to?

-Joe

Ā·Ā·Ā·

On May 31, 2016, at 6:49 PM, Austin Zheng <austinzheng@gmail.com> wrote:

There's definitely the possibility of going off the deep end with complexity like C++, but since we already have tuples as a primitive language feature, I think there's a straightforward language design that enables the most important use cases for variadics. If we have "tuple splatting" for argument forwarding, and some support for iterating tuples, like we briefly discussed in the context of (4 x Int) fixed-sized homogeneous tuples, that'd probably be enough.

I read the original proposal, started writing up a response along these lines, and then scrolled up to see what others had said. I'm glad you agree!

Here's my sketch.

* * *

In general, my preferred direction for this feature would tie variadics closely to tuples, and variadic types closely to tuple types. To wit:

1. We should dust off the old tuple indexing proposal (I actually forgot it was never reviewed) and get it through, along with tuple `count`, `map`, and probably a few other Collection-like operations which generate fixed signatures. (I'm going to use a method-style syntax, but a #function-style syntax would work too; we could even introduce a .#method-style syntax.)

Sounds like more compiler magic... rather than trying to reduce it.

Ā·Ā·Ā·

On Jun 1, 2016, at 3:29 AM, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> wrote:

   let tuple: (Int, Int, Int, Int) = (2, 4, 6, 8)
   print(tuple[tuple.0]) // => 6
   print(tuple.map { $0 / 2 }) // => (1, 2, 3, 4)

2. We should allow you to use analogous operators on the type of a tuple, too.

   let value: (Int, String)[1] = "Hello, world!"
   (Int, String).map { $0.Type } // => (Int.Type, String.Type)

3. We should change our existing variadic parameters to create tuples, not Arrays.

   func print(_ items: (Any...), separator: String = "", terminator: String = "\n") {
       items.0 // Yes, that's a thing you can do

4. We should add a splat operator which unpacks tuples into (possibly variadic) parameters.

   print(tuple...)

5. We should allow you to define variadic type parameters.

   // Note: If you had written `items: Items` instead of `items: Items...`, it would've taken a tuple
   // of various LocalizedStringConvertible types.
   func localizedPrint<Items: (LocalizedStringConvertible...)>(_ items: Items..., separator: String = "", terminator: String = "\n") {
       print(items.map { $0.localizedDescription }, separator: separator, terminator: terminator)
   }

6. We should extend splat to unpack tuple types into (possibly variadic) type parameters.

   typealias Pair = (String, Int)
   let table: Dictionary<Pair...> = [:]

(7. Optional pet-peeve fixer, which I will not actually demonstrate: Require unconstrained type parameters to be spelled `T: Any`, not just `T`. This will remove an asymmetry, in that a variable-length tuple of any type has to be spelled `T: (Any...)`, but a single parameter is just spelled `T`.)

What do we end up with here?

Zip:

   struct ZipSequence<Sequences: (Sequence...)>: Sequence {
       typealias Iterator: ZipIterator<Sequences.map { $0.Iterator }...>
       
       var sequences: Sequences
       
       func makeIterator() -> ZipIterator<Sequences...> {
           return ZipIterator.init(sequences.map { $0.makeIterator() }...)
       }
       
       init(_ sequences: Sequences...) {
           self.sequences = sequences
       }
   }
   
   struct ZipIterator<Iterators: (IteratorProtocol...)>: IteratorProtocol {
       typealias Element = Iterators.map { $0.Element }
       
       var iterators: Iterators
       
       init(_ iterators: Iterators...) {
           self.iterators = iterators
       }
       
       mutating func next() -> Element? {
           // Note: It may be too difficult to assign a type to this reduction;
           // something like the proposal's `#invert` may thus be necessary.
           // If it is added, I would hope that an analogous operation would
           // be added to `Sequence`s of `Optional`s.
           let nextValues = iterators.map { $0.next() }.reduce(Optional( () )) { earlier, this in
               guard let earlier = earlier, this = this else {
                   return nil
               }
               return earlier + (this)
           }
           guard let nextValues = nextValues else {
               return nil
           }
           return nextValues
       }
   }

Function application is basically just a use of the splat feature:

   // Note that the `args: Args` here is *not* `...`ed, so it takes a tuple.
   // Meanwhile, the `Args` in `(Args...) -> Result` does have `...`, so it's looking
   // for arguments which that tuple could be splatted into.
   func apply<Args: (Any...), Return>(_ args: Args, to function: (Args...) -> Return) -> Return {
       return function(args...)
   }
   
   func method<Instance, Args: (Args...), Return>(_ name: String, on instance: Instance) -> ((Args...) -> Return)? {
       ...
   }

MultiMap:

   func multiMap<Sequences: (Sequence...), Return>(_ sequences: (Sequences...), transform: (Sequences.map { $0.Iterator.Element }...) -> Return) -> [Return] {
       var returns: [Return] =
       
       // You could do this by manually making iterators, but why bother when we already have the right abstraction?
       for elems in zip(sequences...) {
           returns.append(transform(elems...))
       }
       
       return returns
   }

Advantages of this approach, as I see them:

* Variadics are entirely a creature of parameter lists and type parameter lists; outside of those, they are always represented as a tuple. That means, for instance, that there is no need for variadics to reach into places like variables.

* `...` goes in exactly two places: After a type name within the definition of a tuple type, and after an expression being splatted into a parameter list. There's no proliferation of dots throughout the language or confusing leading-vs.-trailing dots thing.

* Many of these features are useful in non-variadic code. For instance, Collection-like tuples are a feature people want already.

* We stick closer to already-implemented features, rather than inventing a whole lot of completely novel stuff, like `#rest` and `#fold` and `#vector`.

Disadvantages:

* This leans rather heavily on tuple and tuple type features which will probably, at least for now, have to be built into the compiler. (You might be able to make them macros later.)

* This _may_ raise the grim specter of 1-tuples, but I'm not sure about that. (Perhaps even the concrete-tuple members should be hashed, like `#count` and `#map`? That would allow them to be applied to single values.)

--
Brent Royal-Gordon
Architechies

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

This is pretty much where my thinking about the topic has led me as well. I'll resign this topic to pursue some other, hopefully more relevant work, although anyone who wants to continue the discussion is welcome to.

I donā€™t necessarily agree with the reasoning, but I agree with the conclusion. For me, something like variadic generics isnā€™t even be in scope for Swift *4*, because other generics features (e.g., the Matthew Johnsonā€™s list) are already enough for the full Swift 3 releaseā€¦ and probably too much to tackle in a year.

I do think that variadic generics can fit into our dynamic-dispatched implementation model, and am not at all convinced that these problems are better solved by macros, but Iā€™m happy to have that discussion more than a year from now :)

  - Doug

Ā·Ā·Ā·

On May 31, 2016, at 12:56 PM, Austin Zheng via swift-evolution <swift-evolution@swift.org> wrote:

On Tue, May 31, 2016 at 12:49 PM, Chris Lattner <clattner@apple.com <mailto:clattner@apple.com>> wrote:

On May 31, 2016, at 12:17 PM, L Mihalkovic via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

well there is no macro system, and for the moment a clear statement from chris that this is not on the table in the short term. the code in the example looked like run-of-the-mill swift, except for the ā€œā€¦". so that leaves us with swift looking code that would be executed by the compiler, but with nothing particular to tell which parts to and which not. just a thought.

Lets be clear though: variadic generics are not in scope for Swift 3 either.

I definitely donā€™t speak for the rest of the core team, nor have I discussed it with themā€¦ but IMO, this whole feature seems like a better fit for a macro system than it does to complicate the generics system. Unlike C++ā€™s template system, our generics system inherently has runtime / dynamic dispatch properties, and I donā€™t think that shoehorning variadics into it is going to work out well.

-Chris

On May 31, 2016, at 7:59 PM, Austin Zheng <austinzheng@gmail.com <mailto:austinzheng@gmail.com>> wrote:

How so? I'm interested in anything that can get us away from having to generating code at compile-time.

On Tue, May 31, 2016 at 10:04 AM, L. Mihalkovic <laurent.mihalkovic@gmail.com <mailto:laurent.mihalkovic@gmail.com>> wrote:

What's interesting about the code in the manifesto is that it looks very much like "..." is a runtime construct, as opposed to trying the get the compiler to do the heavy lifting.

_______________________________________________
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

Sounds like more compiler magic... rather than trying to reduce it.

Think of it this way: The amount of compiler magic should be at most proportional to the amount of utility granted by that magic. Most of the magic in this design is not directly in service of variadic generics, but rather in service of more general, and more widely useful, features like Collection-like tuples and splatting.

In particular, a lot of the Collection-like tuple stuffā€”which at least has the largest *surface area* of magic in this proposalā€”is, in my opinion, *very* likely to be standard-library-implementable eventually, either with regular code or with macros. It's also the most broadly useful part of it; people have asked for this feature to make C buffers more accessible, to implement fixed-size arrays, and for various other purposes. As I said, I actually forgot that we hadn't gotten that through review already.

Personally, I think the gains for each feature I discuss are well worth their costs in magic.

Ā·Ā·Ā·

--
Brent Royal-Gordon
Architechies

You know, I'm not a big fan of the `&` syntax people are pushing in the `Any<>` thread,

Finally, a kindred soul!

but if you ignore the Ceylon people begging for union types, I think a sensible alternative meaning for `|` would be "all common supertypes of these types". Then you could write:

  // Bottom here is the bottom type: the subtype of all types.
  (Int, String, Bool).reduce(Bottom, combine: |)

And you'll end up with something like:

  Equatable & Hashable & _Reflectable

Which are the three protocols all of those types support. If they'd supported no common protocols, it would've ended up with `Any`. (Interestingly, this is arguably the same operation which should be used to determine the return value of tuple subscripting.)

This is great for a tuple whose types are known at compile-time, but if you were building a variadic generic type your variadic generic parameters would probably be constrained by the same sorts of type-equality, conformance, and subtyping relations that your normal parameters are today. In that case, it would be useful to have a notion of "this function's generic constraints for T" and "that function's generic constraints for U" line up such that T is a subtype of U, hence we have a useful, compile-time-knowable lower bound for the argument type of a function designed to reduce the members of a variadic generic tuple. You could use this same machinery to convert the bounds into a generalized existential, allowing for a non-generic reducer.

Of course, nothing about having this feature *requires* that we use `&` and `|`; that was just the inspiration for it.

Other questions (inherent to any proposal) would be:

- How do we resolve the impedance mismatch between tuples and function argument lists? Is it even worth trying to resolve this mismatch, given that argument lists are intentionally not intended to mirror tuples?

As far as I know, tuples support a subset of argument list features. (For instance, they don't support default values.) So if you splat a tuple into a parameter list, the worst case is that you won't get to use features like those.

One mismatch is that tuples barely care about their argument labels, while parameter lists select overloads on them. My temptation would be to require you to disambiguate with `(x:y:z)` syntax if you were splatting in an unclear way.

  let triple = (0, 10, 2)
  
  stride(triple...) // Illegal due to ambiguity; write one of these:
  stride(from:to:by:)(triple...)
  stride(from:through:by:)(triple...)

I tested this - calling a function using the fully-qualified name works, but the argument list you provide still needs the parameter labels, which are redundant because they're part of the fully-qualified name. So you'd need: "stride(from:to:by:)(from:0, to:10, by: 2)". Removing this restriction would be a good first step.

Perhaps inout params of type T could be somehow passed as a pair (T, (T) -> ()), where the first item is the input value and the second item is a writeback function representing the 'out' part of inout.

I've no ideas for default values.

One useful thing here is that the arity and types of a tuple are known at compile time, so we can figure out ahead of time how to interpret the call. That wouldn't be the case if you could splat arrays.

(Incidentally, we might want to offer a pseudo-failable initializer to create a tuple from a sequence:

  if let triple = (Int, Int, Int)(intArray) {
    return stride(from:to:by:)(triple...)
  }

That would indirectly allow you to splat the contents of an array into a parameter list.)

- As you said, how do variadic generics work in the 0- and 1-member cases?

I don't think 0-tuples are a big deal, except in that there's no good starting value for certain reductions. Adding a bottom type (as I did in the `reduce` example above) would fix that.

1-tuples are a bigger problem, because if you have a parameter like `(Any...)`, you can't afford to interpret `((Int, String))` as `(Int, String)`. It might be possible to support 1-tuples only in contexts where you're using a variadic tuple, but I'm kind of skeptical of that idea.

Personally, I wish we'd just acknowledge `(SomeType)` (or maybe `(SomeType, )`) as something different from `SomeType` and stop fretting. Sure, it's a semi-useless degenerate case, but so are one-case `enum`s and `Optional<Void>`s, and we don't ban those. Banning `T -> U` syntax has already removed one of the sources of ambiguity here.

I agree that 1-ples would make a lot of things cleaner. Did any of the proposals on the topic ever get to the PR stage?

Ā·Ā·Ā·

On May 31, 2016, at 9:22 PM, Brent Royal-Gordon <brent@architechies.com> wrote:

--
Brent Royal-Gordon
Architechies

I agree that this is a better design for Swift than the monstrosity I started out with.

The "biggest" technical challenge I see is being able to type a reduction sort of operator on a heterogenous tuple based on on whatever protocols and constraints are common to its constituent members. For example:

// Every Tn in T... is Fooable and Barrable
let x : (T...)
reduce(x, reducer, startingValue)

func reducer<X : ???>(startingValue: U, eachMemberOfT: X) -> U { ... }

How do we bound ??? such that 'reducer' is useful while still being statically type sound? Honestly, that's the most interesting question to me. Generalized existentials might help with that.

If every T is Fooable and Barrable, couldn't `eachMemberOfT` be (inout U, protocol<Fooable, Barrable>) -> ()?

Other questions (inherent to any proposal) would be:

- How do we resolve the impedance mismatch between tuples and function argument lists? Is it even worth trying to resolve this mismatch, given that argument lists are intentionally not intended to mirror tuples?

The impedance mismatch between function arguments and tuples is superficial. You ought to be able to splat and bind tuples into function arguments, e.g.:

  let args = (1, 2)
  foo(bar:bas:)(args...)

  func variadicFn<T: Runcible...>(_ args: T...) { ā€¦ }

Going this direction is relatively straightforward. The impedance mismatch is trickier when you want to do more than that. For example, it would be extremely useful to come up with some way to wrap a function that has parameters with default arguments without requiring callers of the wrapped function to supply arguments for the defaulted parameters. Any ideas on how to solve that?

Ā·Ā·Ā·

On Jun 1, 2016, at 8:18 AM, Joe Groff via swift-evolution <swift-evolution@swift.org> wrote:

On May 31, 2016, at 6:49 PM, Austin Zheng <austinzheng@gmail.com> wrote:

- As you said, how do variadic generics work in the 0- and 1-member cases?

What problem are you referring to?

-Joe

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