> On Jan 20, 2017, at 6:07 AM, David Sweeris <daveswee...@mac.com> wrote: > > > On Jan 9, 2017, at 02:13, Charlie Monroe via swift-evolution > <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote: > >> I came across something that I'm not sure it's a bug or by design and if >> it's by design, whether this should be discussed here. >> >> Example: >> >> class Foo { >> init(number: Int) { /* ... */ } >> } >> >> let closure = Foo.init(number:) // (Int) -> Foo >> [1, 2, 3].map(closure) // [Foo, Foo, Foo] >> >> This works great until the initializer gets a default argument: >> >> class Foo { >> init(number: Int, string: String = "") { /* ... */ } >> } >> >> // Error: Foo has no member init(number:) >> let closure = Foo.init(number:) >> >> I was wondering if we could get closures to methods without the default >> arguments. Currently, this needs to be worked around by e.g. creating a >> second closure that invokes the method without the default arguments: >> >> let closure: (Int) -> Foo = { Foo(number: $0) } >> >> But to me it seems like something that should work "out of the box". >> >> Thoughts? > > IIRC, this issue was raised a while ago, and as best as I recall the gist of > the answer was that default arguments are implemented at the call site, and > because of that you can't pass a function with default arguments to something > expecting a function with fewer arguments even though the two calls look > identical in the source code. > > It causes other issues, too. For instance, if we have > protocol Initable { init() } > And > struct Foo { init(_ x: Int = 0) {} } > We're left in an odd situation where `Foo` can't meaningfully conform to > `Initable` because while "init(_: Int = 0)" is not the same as "init()", if > you add a "init()" to `Foo` > you'll get an ambiguous somethingerather error because there's no mechanism > for the compiler to know whether you want the actual "0 argument" function or > the "1 argument with 1 default value" function. >
Sure, but in the case of the closure, it shouldn't be a major issue for the compiler to automatically generate a "proxy" closure that would call the implementation with supplied parameters + rest as default - just like with the current workaround. If no one thinks that this is something that needs to go through the evolution process (in case there is e.g. a good reason why this shouldn't work), I'll just file this as a bug/enhancement request at bugs.swift.org <http://bugs.swift.org/>. > Aside from re-architecting the default argument system (which I'm not even > sure is possible, let alone a good idea), I think I see couple ways forward > for the protocol conformance issue. Both have downsides, though. > > 1) Require any potentially conflicting protocol functions to be in an > extension so the compiler knows what's going on, have "Foo()" call the one > defined in the type, and use "(Foo as Initable)()" for the protocol version > defined in an extension. This could get real confusing real fast if people > don't realize there's two functions with, as far as they can tell, the same > signature. > > 2) Add default argument support to protocols. The syntax that makes sense to > me would be something like > protocol Bar { > func baz(_: Int = _) > } > On the downside, I suspect this would necessarily add a phantom "Self or > associated type requirement" so that the compiler could have a way to get at > each implementation's default value. It's not ideal... You'd get an error > kinda out of the blue if you tried to use the function non-generically, but > at least you couldn't have a function change out from under you. > > - Dave Sweeris
_______________________________________________ swift-evolution mailing list swift-evolution@swift.org https://lists.swift.org/mailman/listinfo/swift-evolution