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