This sort of “it compiles if it’s syntactically valid, regardless of declared 
constraints” thing is deliberately avoided in Swift’s generics design with good 
reason; it’s possible that in this instance there are no problems, but I’m 
skeptical. 

Sent from my iPhone

> On Nov 25, 2017, at 1:16 PM, Xiaodi Wu via swift-evolution 
> <swift-evolution@swift.org> 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.
> 
>> 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