Really like Tony’s suggestion, much cleaner than yet another annotation rammed 
into the signature. Also the idea of a static factory that could accept 
previously initialized arguments would be very powerful. 

-- Howard.

> On 26 Nov 2017, at 9:25 am, Tony Allevato via swift-evolution 
> <swift-evolution@swift.org> wrote:
> 
>> On Sat, Nov 25, 2017 at 1:16 PM Xiaodi Wu <xiaodi...@gmail.com> wrote:
>> On Sat, Nov 25, 2017 at 15:06 Matthew Johnson <matt...@anandabits.com> wrote:
>>>> On Nov 25, 2017, at 1:28 PM, Tony Allevato via swift-evolution 
>>>> <swift-evolution@swift.org> wrote:
>>>> 
>>>> On Fri, Nov 24, 2017 at 7:18 PM Xiaodi Wu via swift-evolution 
>>>> <swift-evolution@swift.org> wrote:
>>>> 
>>>> 
>>>> 
>>>>> It's kludgy, but we could have something like:
>>>>> 
>>>>> ```
>>>>> @defaultArgument(configuration = (), where R.Configuration == Void)
>>>>> @defaultArgument(actionHandler = { _ in }, where R.Action == Never)
>>>>> func makeResource(with configuration: R.Configuration, actionHandler: 
>>>>> @escaping (R.Action) -> Void) -> R { ... }
>>>>> ```
>>>>> 
>>>>> I don't like that we'd be setting a default argument on something 
>>>>> lexically before even encountering it in the declaration, but it's 
>>>>> serviceable.
>>>> 
>>>> 
>>>> What if we could take advantage of the fact that you can have non-constant 
>>>> expressions in default arguments? Overload resolution could already do 
>>>> most of the job—what we need on top of that is a way for the author to say 
>>>> that “if no overload matches, then it’s not an error—just don’t have a 
>>>> default argument in that case”. Something like SFINAE in C++, but more 
>>>> explicit.
>>>> 
>>>> I’m imagining something like this:
>>>> 
>>>> func defaultConfiguration() -> Void {
>>>>   return ()
>>>> }
>>>> 
>>>> func defaultActionHandler() -> (Never) -> Void {
>>>>   return { _ in }
>>>> }
>>>> 
>>>> struct ResourceDescription<R: Resource> {
>>>>   func makeResource(
>>>>     with configuration: R.Configuration =? defaultConfiguration(),
>>>>     actionHandler: @escaping (R.Action) -> Void =? defaultActionHandler()
>>>>   ) -> R {
>>>>     // create a resource using the provided configuration
>>>>     // connect the action handler
>>>>     // return the resource
>>>>   }
>>>> }
>>>> The main difference here is the strawman =? syntax, which would indicate 
>>>> that “the default argument exists if there is a way the RHS can be 
>>>> satisfied for some instances of the generic arguments; otherwise, there is 
>>>> no default”, instead of today’s behavior where it would be an error. There 
>>>> could be multiple overloads of defaultConfiguration and 
>>>> defaultActionHandler (even ones that are themselves generic) and it would 
>>>> do the right thing when there are matches and when there aren’t.
>>>> 
>>>> I like this approach because it mostly takes advantage of existing 
>>>> language features and is fairly lightweight in terms of how it’s expressed 
>>>> in code compared to regular default arguments—we’d just need to design the 
>>>> new operator and type-checker logic around it.
>>>> 
>>> 
>>> This is an interesting approach.  One advantage to something in this 
>>> direction is that it could support defining different defaults for the same 
>>> argument under different constraints by overloading the default argument 
>>> factories on their return type.
>>> 
>>> One concern I have is that it doesn’t allows us to clearly define under 
>>> which constraints a default argument is available.  I suspect this might be 
>>> problematic especially for public interfaces where source compatibility is 
>>> a concern.  
>> 
>> It's certainly an interesting idea but it would suggest that the constraints 
>> under which a default argument is available can change at runtime. I'm 
>> concerned, like you, that this is difficult to reason about. It is still 
>> unclear to me how widespread the underlying issue is that requires 
>> conditional default arguments, but the conversation thus far has been about 
>> compile-time constraints and Tony's design seems to envision much more than 
>> that.
> 
> This runtime/reasoning problem already exists today with default arguments, 
> because you can write something like this:
> 
> struct Foo {
>   static var defaultExponent = 2.0
> 
>   func raise(_ x: Double, to exponent: Double = defaultExponent) {
>     print(pow(x, exponent))
>   }
> }
> 
> Foo().raise(4)  // "16.0"
> Foo.defaultExponent = 3.0
> Foo().raise(4)  // "64.0"
> Swift lets you write a default value expression that references static (but 
> not instance) vars of the enclosing type, as well as anything else that’s 
> visible from that expression’s scope. Should people do this? Probably not, 
> for the reasons that you described.
> 
> But the point is that my example is no more harmful or difficult to reason 
> about than default arguments in the language today. My proposed solution in 
> no way changes the runtime behavior of default argument expressions. I’m not 
> envisioning anything more than what default arguments can already do except 
> for adding a way to choose different default factories (or choose none 
> without error) based on the static types of the generic arguments that are 
> bound at a particular call site.
> 
> 
>> 
>>> I think I prefer Xiaodi’s suggestion for that reason.  His approach could 
>>> also support multiple defaults for the same parameter as long as the 
>>> constraints are not allowed to overlap (overlapping constraints would 
>>> result in ambiguity similar to ambiguous overload resolution) or an 
>>> explicit argument is required if they do.
>>> 
>>>> 
>>>> 
>>>> 
>>>>> 
>>>>> 
>>>>>> On Fri, Nov 24, 2017 at 8:36 PM, T.J. Usiyan via swift-evolution 
>>>>>> <swift-evolution@swift.org> wrote:
>>>>>> I am all for this. are many types where there is an obvious 'zero' or 
>>>>>> 'default' value and the ability to express "use that when possible" 
>>>>>> without an overload is welcome.
>>>>>> 
>>>>>> 
>>>>>> The best thing that I can think of right now, in terms of syntax, is 
>>>>>> actually using @overload
>>>>>> 
>>>>>> ```
>>>>>> struct ResourceDescription<R: Resource> {
>>>>>> 
>>>>>>   func makeResource(with configuration: R.Configuration, actionHandler: 
>>>>>> @escaping (R.Action) -> Void) -> R 
>>>>>>  @overload(R.Configuration == Void) func makeResource(actionHandler: 
>>>>>> @escaping (R.Action) -> Void) -> R
>>>>>> @overload(R.Action == Never)  func makeResource(with configuration: 
>>>>>> R.Configuration) -> R
>>>>>> {
>>>>>>     // create a resource using the provided configuration
>>>>>>     // connect the action handler
>>>>>>     // return the resource
>>>>>>   }
>>>>>> }
>>>>>> ```
>>>>>> 
>>>>>> 
>>>>>> This isn't great though…
>>>>>> 
>>>>>>> On Fri, Nov 24, 2017 at 6:11 PM, Matthew Johnson via swift-evolution 
>>>>>>> <swift-evolution@swift.org> wrote:
>>>>>>> As mentioned in my prior message, I currently have a PR open to update 
>>>>>>> the generics manifesto (https://github.com/apple/swift/pull/13012).  I 
>>>>>>> removed one topic from that update at Doug Gregor’s request that it be 
>>>>>>> discussed on the list first.  
>>>>>>> 
>>>>>>> The idea is to add the ability to make default arguments conditional 
>>>>>>> (i.e. depend on generic constraints).  It is currently possible to 
>>>>>>> emulate conditional default arguments using an overload set.  This is 
>>>>>>> verbose, especially when several arguments are involved.  Here is an 
>>>>>>> example use case using the overload method to emulate this feature:
>>>>>>> 
>>>>>>> ```swift
>>>>>>> protocol Resource {
>>>>>>>   associatedtype Configuration
>>>>>>>   associatedtype Action
>>>>>>> }
>>>>>>> struct ResourceDescription<R: Resource> {
>>>>>>>   func makeResource(with configuration: R.Configuration, actionHandler: 
>>>>>>> @escaping (R.Action) -> Void) -> R {
>>>>>>>     // create a resource using the provided configuration
>>>>>>>     // connect the action handler
>>>>>>>     // return the resource
>>>>>>>   }
>>>>>>> }
>>>>>>> 
>>>>>>> extension ResourceDescription where R.Configuration == Void {
>>>>>>>   func makeResource(actionHandler: @escaping (R.Action) -> Void) -> R {
>>>>>>>     return makeResource(with: (), actionHandler: actionHandler)
>>>>>>>   }
>>>>>>> }
>>>>>>> 
>>>>>>> extension ResourceDescription where R.Action == Never {
>>>>>>>   func makeResource(with configuration: R.Configuration) -> R {
>>>>>>>     return makeResource(with: configuration, actionHandler: { _ in })
>>>>>>>   }
>>>>>>> }
>>>>>>> 
>>>>>>> extension ResourceDescription where R.Configuration == Void, R.Action 
>>>>>>> == Never {
>>>>>>>   func makeResource() -> R {
>>>>>>>     return makeResource(with: (), actionHandler: { _ in })
>>>>>>>   }
>>>>>>> }
>>>>>>> 
>>>>>>> ```
>>>>>>> 
>>>>>>> Adding language support for defining these more directly would 
>>>>>>> eliminate a lot of boilerplate and reduce the need for overloads.  Doug 
>>>>>>> mentioned that it may also help simplify associated type inference 
>>>>>>> (https://github.com/apple/swift/pull/13012#discussion_r152124535).
>>>>>>> 
>>>>>>> The reason that I call this a pre-pitch and one reason Doug requested 
>>>>>>> it be discussed on list is that I haven’t thought of a good way to 
>>>>>>> express this syntactically.  I am interested in hearing general 
>>>>>>> feedback on the idea.  I am also looking for syntax suggestions.
>>>>>>> 
>>>>>>> Matthew
>>>>>>> 
>>>>>>> _______________________________________________
>>>>>>> swift-evolution mailing list
>>>>>>> swift-evolution@swift.org
>>>>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>>>>> 
>>>>>> 
>>>>>> 
>>>>>> _______________________________________________
>>>>>> swift-evolution mailing list
>>>>>> swift-evolution@swift.org
>>>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>>>> 
>>>>> 
>>>>> _______________________________________________
>>>>> swift-evolution mailing list
>>>>> swift-evolution@swift.org
>>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>> 
>>>> 
>>>> _______________________________________________
>>>> swift-evolution mailing list
>>>> swift-evolution@swift.org
>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
> _______________________________________________
> 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

Reply via email to