[Pitch] #dup -- a duplication "macro"(?)

When coming up with new array interfaces, I had some array to/from tuple conversion functions:

func array<T, U…>(from: (T, …U)) -> [1 + #countOf(U) ; T] allwhere U == T

The problem is going the other way:

func tuple<T, N: Int>(from: [N; T]) -> ???

The tuple will be a bunch of “T,” but the count mechanically added depends on compiler-visible number N. Well, since this is part of a proposal that already mutates the language, I thought why not add a primitive operation by fiat:

func tuple<T, N: Int>(from: [N; T]) -> ( #dup(N; T) )

where “#dup” dumps a comma-separated list repeating the right-side entity with a multiplicity of the left-side value. The left-side value has to be a compiler constant expression. I was going to have the right side be an arbitrary token sequence, but I think it’s better for now to limit it to either a type (or similar) or an expression. Obviously, the receiver has to compatible with whatever being dumped there.

Could we do better than simple repetition? What if we define a “$$n” unit, where “n” is a nonnegative integer. For each comma-separated item, the unit will be replaced by increasing compiler-constant integers from zero. If using an expression, maybe you can call a function on the double-dollar value to get your own custom values there. This can be expanded to types once value-based generic parameters get added.

When there are nested #dup calls, the double-dollar unit refers to the counter for the innermost #dup. Maybe there can be a triple-dollar unit for the immediately enclosing #dup. Even quadruple- or more-dollar units for the outer levels. (Hopefully, nothing more that one level would be needed.)

Later, I remembered the "( 6 * TupleMemberType )” syntax for repeating a type within a tuple that's sometimes suggested. The #dup facility can be seen as a generalized version of that quasi-array-specific idea.

···


Daryle Walker
Mac, Internet, and Video Game Junkie
darylew AT mac DOT com

We've been talking about adding Variadic Generic Parameters for a while, and I'm pretty sure that the functionality you're suggesting here would be a subset of that. We're just waiting for it to come into scope.

- Dave Sweeris

···

On Jul 31, 2017, at 7:23 PM, Daryle Walker via swift-evolution <swift-evolution@swift.org> wrote:

When coming up with new array interfaces, I had some array to/from tuple conversion functions:

func array<T, U…>(from: (T, …U)) -> [1 + #countOf(U) ; T] allwhere U == T

The problem is going the other way:

func tuple<T, N: Int>(from: [N; T]) -> ???

The tuple will be a bunch of “T,” but the count mechanically added depends on compiler-visible number N. Well, since this is part of a proposal that already mutates the language, I thought why not add a primitive operation by fiat:

func tuple<T, N: Int>(from: [N; T]) -> ( #dup(N; T) )

where “#dup” dumps a comma-separated list repeating the right-side entity with a multiplicity of the left-side value. The left-side value has to be a compiler constant expression. I was going to have the right side be an arbitrary token sequence, but I think it’s better for now to limit it to either a type (or similar) or an expression. Obviously, the receiver has to compatible with whatever being dumped there.

Could we do better than simple repetition? What if we define a “$$n” unit, where “n” is a nonnegative integer. For each comma-separated item, the unit will be replaced by increasing compiler-constant integers from zero. If using an expression, maybe you can call a function on the double-dollar value to get your own custom values there. This can be expanded to types once value-based generic parameters get added.

When there are nested #dup calls, the double-dollar unit refers to the counter for the innermost #dup. Maybe there can be a triple-dollar unit for the immediately enclosing #dup. Even quadruple- or more-dollar units for the outer levels. (Hopefully, nothing more that one level would be needed.)

Later, I remembered the "( 6 * TupleMemberType )” syntax for repeating a type within a tuple that's sometimes suggested. The #dup facility can be seen as a generalized version of that quasi-array-specific idea.

I don’t think this functionality is covered by variadic generic parameters.

···

On Jul 31, 2017, at 10:38 PM, David Sweeris <davesweeris@mac.com> wrote:

On Jul 31, 2017, at 7:23 PM, Daryle Walker via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

The tuple will be a bunch of “T,” but the count mechanically added depends on compiler-visible number N. Well, since this is part of a proposal that already mutates the language, I thought why not add a primitive operation by fiat:

func tuple<T, N: Int>(from: [N; T]) -> ( #dup(N; T) )

where “#dup” dumps a comma-separated list repeating the right-side entity with a multiplicity of the left-side value. The left-side value has to be a compiler constant expression. I was going to have the right side be an arbitrary token sequence, but I think it’s better for now to limit it to either a type (or similar) or an expression. Obviously, the receiver has to compatible with whatever being dumped there.

We've been talking about adding Variadic Generic Parameters for a while, and I'm pretty sure that the functionality you're suggesting here would be a subset of that. We're just waiting for it to come into scope.


Daryle Walker
Mac, Internet, and Video Game Junkie
darylew AT mac DOT com

Upon waking up, I realized I got this part of the idea completely wrong. Within the right side of a #dup, there is only one counter, so numbers wouldn’t be necessary after the “$$”.

However, we could use numbers to replace the triple-, quadruple-, etc. dollar-sign idea. So “$$0” is the counter for the current #dup, “$$1” is the counter for the immediately surrounding #dup, and higher numbers go for outer layers. Upon expansion, “$$0” goes to the index number of the comma-separated entity, while “$$n” goes to “$$(n - 1)”. It’s an error to still have double-dollar symbols remaining after the outermost #dup is expanded.

Oh, the right side of the #dup can take a type, an expression, or a comma-separated list of one of those.

Here’s an example using theoretical fixed-size arrays:

let tupleOf12 = ( (2, 3, 5, 7), (4, 6, 8, 9), (10, 11, 12, 1) )
let arrayOf12 = { 3, 4 ; #dup(3; #dup(4; tupleOf12 . $$1 . $$0 ) ) }
assert( tupleOf12.0.0 == arrayOf12[0, 0] ) // 2
//…
assert( tupleOf12.2.3 == arrayOf12[2, 3] ) // 1

So resolving the inner #dup gives:

#dup(3; tupleOf12 . $$0 . 0, tupleOf12 . $$0 . 1, tupleOf12 . $$0 . 2, tupleOf12 . $$0 . 3 )

And doing the remaining #dup gives:

tupleOf12 . 0 . 0, tupleOf12 . 0 . 1, tupleOf12 . 0 . 2, tupleOf12 . 0 . 3, tupleOf12 . 1 . 0, tupleOf12 . 1 . 1, tupleOf12 . 1 . 2, tupleOf12 . 1 . 3, tupleOf12 . 2. 0, tupleOf12 . 2 . 1, tupleOf12 . 2 . 2, tupleOf12 . 2 . 3

···

On Jul 31, 2017, at 10:23 PM, Daryle Walker via swift-evolution <swift-evolution@swift.org> wrote:

Could we do better than simple repetition? What if we define a “$$n” unit, where “n” is a nonnegative integer. For each comma-separated item, the unit will be replaced by increasing compiler-constant integers from zero. If using an expression, maybe you can call a function on the double-dollar value to get your own custom values there. This can be expanded to types once value-based generic parameters get added.

When there are nested #dup calls, the double-dollar unit refers to the counter for the innermost #dup. Maybe there can be a triple-dollar unit for the immediately enclosing #dup. Even quadruple- or more-dollar units for the outer levels. (Hopefully, nothing more that one level would be needed.)


Daryle Walker
Mac, Internet, and Video Game Junkie
darylew AT mac DOT com

After a few hours, I figured out what was bugging me. Variadic generic parameters, and the existing variadic function parameters, CONSUME arbitrarily long comma-separated lists. The #dup facility PRODUCES those kinds of lists. The features are duals, not the same. The features can synergize.

···

On Aug 1, 2017, at 9:56 AM, Daryle Walker <darylew@mac.com> wrote:

On Jul 31, 2017, at 10:38 PM, David Sweeris <davesweeris@mac.com <mailto:davesweeris@mac.com>> wrote:

On Jul 31, 2017, at 7:23 PM, Daryle Walker via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

The tuple will be a bunch of “T,” but the count mechanically added depends on compiler-visible number N. Well, since this is part of a proposal that already mutates the language, I thought why not add a primitive operation by fiat:

func tuple<T, N: Int>(from: [N; T]) -> ( #dup(N; T) )

where “#dup” dumps a comma-separated list repeating the right-side entity with a multiplicity of the left-side value. The left-side value has to be a compiler constant expression. I was going to have the right side be an arbitrary token sequence, but I think it’s better for now to limit it to either a type (or similar) or an expression. Obviously, the receiver has to compatible with whatever being dumped there.

We've been talking about adding Variadic Generic Parameters for a while, and I'm pretty sure that the functionality you're suggesting here would be a subset of that. We're just waiting for it to come into scope.

I don’t think this functionality is covered by variadic generic parameters.


Daryle Walker
Mac, Internet, and Video Game Junkie
darylew AT mac DOT com

Ah, ok, I see what you're saying now... I hadn't considered that the as-yet-hypothetical VGP proposal wouldn't allow for both consuming and producing VGP lists.

- Dave Sweeris

···

On Aug 2, 2017, at 21:39, Daryle Walker <darylew@mac.com> wrote:

On Aug 1, 2017, at 9:56 AM, Daryle Walker <darylew@mac.com> wrote:

On Jul 31, 2017, at 10:38 PM, David Sweeris <davesweeris@mac.com> wrote:

On Jul 31, 2017, at 7:23 PM, Daryle Walker via swift-evolution <swift-evolution@swift.org> wrote:

The tuple will be a bunch of “T,” but the count mechanically added depends on compiler-visible number N. Well, since this is part of a proposal that already mutates the language, I thought why not add a primitive operation by fiat:

func tuple<T, N: Int>(from: [N; T]) -> ( #dup(N; T) )

where “#dup” dumps a comma-separated list repeating the right-side entity with a multiplicity of the left-side value. The left-side value has to be a compiler constant expression. I was going to have the right side be an arbitrary token sequence, but I think it’s better for now to limit it to either a type (or similar) or an expression. Obviously, the receiver has to compatible with whatever being dumped there.

We've been talking about adding Variadic Generic Parameters for a while, and I'm pretty sure that the functionality you're suggesting here would be a subset of that. We're just waiting for it to come into scope.

I don’t think this functionality is covered by variadic generic parameters.

After a few hours, I figured out what was bugging me. Variadic generic parameters, and the existing variadic function parameters, CONSUME arbitrarily long comma-separated lists. The #dup facility PRODUCES those kinds of lists. The features are duals, not the same. The features can synergize.

I just upload a rough proposal at <https://gist.github.com/CTMacUser/44afa75e379ec70201391af3a39bcdeb&gt;\.

···

On Aug 3, 2017, at 12:39 AM, Daryle Walker <darylew@mac.com> wrote:

After a few hours, I figured out what was bugging me. Variadic generic parameters, and the existing variadic function parameters, CONSUME arbitrarily long comma-separated lists. The #dup facility PRODUCES those kinds of lists. The features are duals, not the same. The features can synergize.


Daryle Walker
Mac, Internet, and Video Game Junkie
darylew AT mac DOT com