[swift-evolution] Variadic generics discussion

Matthew Johnson matthew at anandabits.com
Sun May 29 07:00:49 CDT 2016



Sent from my iPad

> On May 29, 2016, at 1:22 AM, Austin Zheng <austinzheng at gmail.com> wrote:
> 
> Thank you for reading through the proposal! 
> 
>> On May 28, 2016, at 7:41 PM, Matthew Johnson <matthew at anandabits.com> wrote:
>> 
>> These are some very good and clearly articulated examples.  Great work!  This section is important because variadics are somewhat complicated and it is important to show people why we want them and what problems they can solve.
> 
> Any more practical use cases you can come up with (preferably ones that are distinct from the few we have now) would be greatly appreciated.
> 
> My thinking is that it's best to keep the feature as described in this proposal as lightweight as possible, proposing only enough expressiveness so that most reasonable use cases can be expressed. There are two reasons for that:
> 
> - Design and implementation burden relative to benefit. This is not a top-priority feature in the manifesto, and will be competing with at least two or three other features for resources. It's also quite complicated, as-is. It will affect how Swift handles resilience. [*]
> - This proposal should not become a variadic generics proposal with a half-thought-out compile time metaprogramming scheme hanging off it. What Swift gets in terms of macros, code generation, or compile-time expressions deserves a conversation of its own eventually.

Very much agree with the comments about compile time meta programming here.  I'm really looking forward to that but we can do far better than C++ here.  

> 
> More concretely, D has a "static if" construct (https://dlang.org/variadic-function-templates.html). It looks really nice - you could write a n-arity function that generates a `print("Hello, Matthew")` only if its arity is 3. I'm sure there are many use cases for it. Is building something similar worth spending time for during the Swift 3.x timeframe? Probably not, especially if it could be implemented in the future and the existing variadic generic semantics seamlessly extended to work with it.
> 
>> 
>>> 
>>> There is a lot of scope for design refinements, and even for alternative designs. With enhanced existentials, there was already an informal consensus that the feature would involve composing some protocols and class requirements, and placing constraints on the associated types, and most everything else was working out the various implications of doing so. That's not true for this feature.
>>> 
>>> In particular, I'm interested to see if there are similarly expressive designs that use exclusively tuple-based patterns and no parameter packs. I think Rust once considered a similar approach, although their proposal ended up introducing a parameter-pack like construct for use with fn application: https://github.com/rust-lang/rfcs/issues/376
>> 
>> As far as I can tell, the way you are approaching `apply` would not allow the default arguments of the function passed as `function` to be used when calling `apply`.  Arguments would have to be provided for all parameters when the function is invoked through apply.
> 
> Yes. There are a lot of issues right now with the idea of using a value pack or a tuple to call a function, and most of them apply to the tuple splat discussion that took place a few months ago. Namely, the idea of a tuple or 'vector' of values does not map cleanly to Swift's function parameter conventions. You have inout params, params with default values, argument labels, and other stuff that tuples can't represent cleanly or at all.
> 
>> 
>> I know that this difficulty is not directly related to variadic generics, but it does demonstrate a limitation of this approach to forwarding.
>> 
>> I have already run into a use case where I would like to accept a function and a pack of arguments, store the arguments, be able to compare them for equality, and later invoke the function with them.  However, in order for this approach to make sense in my use case it would be essential that the user *not* need to explicitly provide arguments for parameters with defaults.
>> 
>> I bring this up in hopes that we might try to explore designs that would support this use case, and at least give it some consideration.  I’m trying to think of ways to make this work but haven’t come up with anything obvious yet.
> 
> I do want to explore designs in this space, and I think we will need to figure it out at some point.
> 
> If a good solution cannot present itself in the time frame, I'd be willing to punt for the purposes of this proposal.

I am ok with that as long as we can see a path forward to a more robust forwarding solution that can sit beside the variadic generics feature.  It would be unfortunate if we move ahead and later find out that we did something that makes more robust forwarding more difficult to design for one reason or another.

> My idea of a (sad, awful) fallback solution is to prohibit apply on functions with inout params, require an argument for every argument in the formal parameter list, and allow a fully qualified function reference to be called without re-specifying the argument labels:
> 
> struct Foo {
>   func myFunc(x: Int, y: Int) { }
>   func myFunc(x: Int, z: Int) { }
> }
> 
> let x = Foo()
> let theFunc = x.myFunc(_:y:)
> // Cannot do this now
> x.myFunc(_:y:)(1, 2)
> // Have to do this:
> x.myFunc(_:y:)(1, y: 2)  // but 'y' is redundant on right; this was discussed during the tuple splat thread

I haven't tried this.  It actually surprised me.  I thought the unlabeled tuple would implicitly work where a labeled tuple with the same sequence of member types was required.

> 
> // In the future...
> x.someFunc(_:y:z...:)(1, 2, myPack...)
> 
>> 
>> -Matthew
> 
> [*] On a tangential topic, how is Swift going to handle generics across module boundaries in the future? People are complaining that their library generics code is too slow because specialization is impossible, and specialization only happens on stdlib generic types because of some hacks. https://github.com/lorentey/BTree#generics notes that @_specialize might be exposed as an attribute for library author use in the future. It might be the case that every variadic generic type might need to be @_specialize by default, because I can't imagine a variadic equivalent to the dynamic-dispatch solution currently used to implement regular generics without specialization.

Agree that cross module specialization (and WPO generally) is very important. When modules have a nontrivial performance cost (inability to specialize generics) their use is discouraged to some degree.

> 
>>> 
>>> Feedback would be greatly appreciated. Again, be unsparing.
>>> 
>>> Best,
>>> Austin
>>> 
>>> _______________________________________________
>>> swift-evolution mailing list
>>> swift-evolution at swift.org
>>> https://lists.swift.org/mailman/listinfo/swift-evolution
> 
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160529/c59f1556/attachment.html>


More information about the swift-evolution mailing list