> On Nov 28, 2017, at 10:06 AM, Tony Allevato <tony.allev...@gmail.com> wrote:
> 
> 
> 
> On Mon, Nov 27, 2017 at 10:32 PM Slava Pestov <spes...@apple.com 
> <mailto:spes...@apple.com>> wrote:
> Hi Tony,
> 
> So if my understanding is correct, the basic proposal is the following:
> 
> func id<T>(t: T ?= T.defaultValue) { return t }
> 
> extension Int { static var defaultValue = 0 }
> 
> extension String { static var defaultValue = “” }
> 
> id() as Int // returns 0
> id() as String // returns “”
> id() as SomeRandomType // fails to type check — no default argument
> 
> I don’t understand what would happen if the caller is itself generic though, 
> for example:
> 
> callsID<T>(_ t: T) {
>   _ = id() as T
> }
> 
> It appears that body of callsID() itself cannot type check without knowledge 
> of the concrete T that will be used with this function.
> 
> Thanks for bringing up this example, Slava.
> 
> Unless I'm misunderstanding, the issue you're describing is inherent to the 
> *problem* described in the original post, not to any specific hypothetical 
> syntax for adding the default arguments, correct? In other words, if this was 
> written using extensions as can be done today:
> 
> ```
> struct Foo<T> {
>   func id(t: T) -> T { return t }
> }
> 
> extension Foo where T == Void {
>   func id() -> T { return () }
> }
> 
> extension Foo where T == Int {
>   func id() -> T { return 0 }
> }
> 
> callsID<T>(_ t: T) {
>   _ = Foo().id() as T    // mark
> }
> ```
> 
> The compiler would still reject the marked line because there's no guarantee 
> that T is one of the types that has the necessary overload.
> 
> But now that you've mentioned it, it does have me thinking that this problem 
> might be better left to extensions. In one sense, default arguments are a 
> kind of "overload synthesis”,

They appear to callers as if they were overloads but I think it’s important 
that they actually do so *without* introducing an overload.  Reducing the size 
of an overload set is good for users, library authors and the compiler.  The 
benefits that come to all parties when the size of an overload set is reduced 
is the primary reason I started this thread.

> but on the other hand, there's an expectation that the default value 
> expression is of a single type (or set of related types) known at compile 
> time. Even if it's generic, it still must be expressed in terms of whatever 
> constraints are present on that generic type—you can't use a disjunction of 
> types, but instead have to have a common protocol that would provide some 
> operation.

This should not change for any given default value expression.  This thread 
doesn’t discuss changing that.  I discusses the ability to constrain the 
presence of a default value expression.  While it would be useful to allow 
multiple default value expressions for different constraints the most common 
case will be a single constrained default value expression for any given 
argument.  We could just allow a trailing where clause on the default value 
expression itself like this:

func makeResource(
    with configuration: Configuration = () where Configuration == Void, 
    actionHandler: @escaping (Action) -> Void = { _ in } where Action == Never
)

That addresses the most common cases for this feature with a fairly obvious and 
direct syntax.  It also avoids the potential ambiguity that could arise from 
allowing multiple defaults with different (potentially overlapping) constraints.


>  
> 
> Slava
> 
>> On Nov 27, 2017, at 4:10 PM, Tony Allevato via swift-evolution 
>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>> 
>> I totally agree that that's a good rule in general—I'm not 100% comfortable 
>> making an exception to it for this, but I wanted to start a discussion about 
>> a different approach than had been considered so far.
>> 
>> The idea of forcing the user to acknowledge the explicitness of SFINAE with 
>> a strawman syntax `=?` instead of `=` was a thought experiment to bridge the 
>> wild-west-C++ world of templates and Swift's stricter generics, but I can 
>> definitely understand if even that kind of approach is something that the 
>> core team (who are far more familiar with the C++ side of that coin than I 
>> am) doesn't wish to support. As was pointed out, it's not something Swift 
>> supports anywhere else today.
>> 
>> If we look at it from that point of view, where such a semantic treatment of 
>> generics would not be supported, I think it becomes a lot harder to 
>> rationalize treating this as "default arguments". What you really do have 
>> (and what writing it as constrained extensions makes clear) is additional 
>> overloads, because they only apply to certain subsets of types. If that's 
>> the case, maybe it's the wrong approach to try to turn overloads into 
>> "partial default values".
> 

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to