<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""><div><blockquote type="cite" class=""><div class="">On Nov 28, 2017, at 11:01 AM, Tony Allevato <<a href="mailto:tony.allevato@gmail.com" class="">tony.allevato@gmail.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div dir="ltr" class=""><br class=""><br class=""><div class="gmail_quote"><div dir="ltr" class="">On Tue, Nov 28, 2017 at 8:45 AM Matthew Johnson <<a href="mailto:matthew@anandabits.com" class="">matthew@anandabits.com</a>> wrote:<br class=""></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word" class=""><div class=""><blockquote type="cite" class=""><div class="">On Nov 28, 2017, at 10:06 AM, Tony Allevato <<a href="mailto:tony.allevato@gmail.com" target="_blank" class="">tony.allevato@gmail.com</a>> wrote:</div><br class="m_-7905613941316348268Apple-interchange-newline"><div class=""><div dir="ltr" class=""><br class=""><br class=""><div class="gmail_quote"><div dir="ltr" class="">On Mon, Nov 27, 2017 at 10:32 PM Slava Pestov <<a href="mailto:spestov@apple.com" target="_blank" class="">spestov@apple.com</a>> wrote:<br class=""></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word;line-break:after-white-space" class="">Hi Tony,<div class=""><br class=""></div><div class="">So if my understanding is correct, the basic proposal is the following:</div><div class=""><br class=""></div><div class="">func id<T>(t: T ?= T.defaultValue) { return t }</div><div class=""><br class=""></div><div class="">extension Int { static var defaultValue = 0 }</div><div class=""><br class=""></div><div class="">extension String { static var defaultValue = “” }</div><div class=""><br class=""></div><div class="">id() as Int // returns 0</div><div class=""><div class="">id() as String // returns “”</div><div class="">id() as SomeRandomType // fails to type check — no default argument</div><div class=""><br class=""></div><div class="">I don’t understand what would happen if the caller is itself generic though, for example:</div><div class=""><br class=""></div><div class="">callsID<T>(_ t: T) {</div><div class=""> _ = id() as T</div><div class="">}</div><div class=""><br class=""></div><div class="">It appears that body of callsID() itself cannot type check without knowledge of the concrete T that will be used with this function.</div></div></div></blockquote><div class=""><br class=""></div><div class="">Thanks for bringing up this example, Slava.</div><div class=""><br class=""></div><div class="">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:</div><div class=""><br class=""></div><div class="">```</div><div class="">struct Foo<T> {</div><div class=""> func id(t: T) -> T { return t }</div><div class="">}</div><div class=""><br class=""></div><div class="">extension Foo where T == Void {</div><div class=""> func id() -> T { return () }</div><div class="">}</div><div class=""><br class=""></div><div class="">extension Foo where T == Int {</div><div class=""> func id() -> T { return 0 }</div><div class="">}</div><div class=""><br class=""></div><div class="">callsID<T>(_ t: T) {</div><div class=""> _ = Foo().id() as T // mark</div><div class="">}</div><div class="">```</div><div class=""><br class=""></div><div class="">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.</div><div class=""><br class=""></div><div class="">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”, </div></div></div></div></blockquote><div class=""><br class=""></div></div></div><div style="word-wrap:break-word" class=""><div class=""><div class="">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.</div></div></div><div style="word-wrap:break-word" class=""><div class=""><br class=""><blockquote type="cite" class=""><div class=""><div dir="ltr" class=""><div class="gmail_quote"><div class="">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.</div></div></div></div></blockquote><div class=""><br class=""></div></div></div><div style="word-wrap:break-word" class=""><div class=""><div class="">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.</div></div></div></blockquote><div class=""><br class=""></div><div class="">But that's exactly the distinction that I'm driving at—the more I think about it, the more I have difficulty expressing it cleanly and I think that's because these aren't the same as default arguments—they really are distinct overloads because you're talking about the presence or absence of an argument based on specific constraints instead of something that applies to the function uniformly for all possible types that satisfy the constraint. So what I'm suggesting is that maybe conflating this concept with default arguments is the wrong approach after all.<br class=""></div><div class=""><br class=""></div><div class=""> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word" class=""><div class=""><div class=""> 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:</div><div class=""><br class=""></div><div class="">func makeResource(</div><div class=""> with configuration: Configuration = () where Configuration == Void, </div><div class=""> actionHandler: @escaping (Action) -> Void = { _ in } where Action == Never</div><div class="">)</div><div class=""><br class=""></div><div class="">That addresses the most common cases for this feature with a fairly obvious and direct syntax.</div></div></div></blockquote><div class=""><br class=""></div><div class="">Allowing only one constraint seems arbitrary and I imagine that the immediately following question would be "what if I want more than one?" I wouldn't want to address only part of the problem. My ICU example further up in the thread shows a scenario where I would want defaults for two distinct types (if I also wanted to publicize the general initializer to everyone).<br class=""></div></div></div></div></blockquote><div><br class=""></div><div>Did you really mean “only one constraint” here? Or did you mean “only one default value expression”? These are very different. I would not want to restrict the number of constraints. What I am suggesting is that limiting this to a single (possibly constrained) default value expression presents a relatively obvious syntactic solution.</div><br class=""><blockquote type="cite" class=""><div class=""><div dir="ltr" class=""><div class="gmail_quote"><div class=""><br class=""></div><div class=""> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word" class=""><div class=""><div class=""> It also avoids the potential ambiguity that could arise from allowing multiple defaults with different (potentially overlapping) constraints.</div></div></div></blockquote><div class=""><br class=""></div><div class="">That would be no different than the existing problem of multiple overloads with different (potentially overlapping) constraints, right? </div></div></div></div></blockquote><div><br class=""></div><div>Right, but...</div><br class=""><blockquote type="cite" class=""><div class=""><div dir="ltr" class=""><div class="gmail_quote"><div class="">If what you're looking for is a way to have the compiler automatically synthesize overloads in extensions for you based on certain constraints, I would expect the same restrictions to apply as if you had explicitly written them out long-form.</div></div></div></div></blockquote><div><br class=""></div><div>I specifically *do not* want the compiler to synthesize overloads. I want to get rid of them entirely, not just the code that declares them. What I would like the compiler to do is to synthesize the default value expression at call sites that meet the constraints for the default value expression and omit an explicit argument (exactly as it does for unconstrained default value expressions).</div><div><br class=""></div><div>These are very different things. The latter is not possible in Swift today. It can only be emulated by providing an unnecessarily bloated overload set.</div><div><br class=""></div><div>The more I think about this the more simply allowing a where clause on a default value expression feels like the right thing to do (if we introduce this feature). It doesn’t solve all potential use cases but it does solve the 80% case in an obvious way and doesn’t harm the current workaround in the remaining cases.</div><br class=""><blockquote type="cite" class=""><div class=""><div dir="ltr" class=""><div class="gmail_quote"><div class=""><br class=""></div><div class=""><br class=""></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word" class=""><div class=""><div class=""><br class=""></div><br class=""><blockquote type="cite" class=""><div class=""><div dir="ltr" class=""><div class="gmail_quote"><div class=""> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word;line-break:after-white-space" class=""><div class=""><div class=""><br class=""></div><div class="">Slava</div></div></div><div style="word-wrap:break-word;line-break:after-white-space" class=""><div class=""><div class=""><br class=""><blockquote type="cite" class=""><div class="">On Nov 27, 2017, at 4:10 PM, Tony Allevato via swift-evolution <<a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a>> wrote:</div><br class="m_-7905613941316348268m_-1835373692816656522Apple-interchange-newline"><div class=""><div style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px" class="">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.</div><div style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px" class=""><br class=""></div><div style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px" class="">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.</div><div style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px" class=""><br class=""></div><div style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px" class="">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".</div></div></blockquote></div><br class=""></div></div></blockquote></div></div>
</div></blockquote></div></div></blockquote></div></div>
</div></blockquote></div><br class=""></body></html>