> 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

Reply via email to