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