Re: [swift-evolution] Closures from methods with default args

2017-01-20 Thread Charlie Monroe via swift-evolution

> On Jan 20, 2017, at 6:07 AM, David Sweeris  wrote:
> 
> 
> On Jan 9, 2017, at 02:13, Charlie Monroe via swift-evolution 
> 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 
. 

> 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


Re: [swift-evolution] Closures from methods with default args

2017-01-19 Thread Slava Pestov via swift-evolution

> On Jan 19, 2017, at 9:07 PM, David Sweeris via swift-evolution 
>  wrote:

> 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.
> 
> 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.

I think in this specific example, the best solution is to allow init(_ x: Int = 
0) to witness the init() requirement, and have the compiler emit the necessary 
glue in-between so that a call to the init() requirement calls init(_) with the 
appropriate default value. This will address the ‘ambiguous reference’ issue, 
and should not require too much work to implement. I am also inclined to 
believe this is (mostly) a source-compatible change. It also fits in with the 
current default argument model, but Doug Gregor can correct me if I’m wrong.

If anyone is interested, the code for matching protocol requirements to 
witnesses is in lib/Sema/TypeCheckProtocol.cpp, matchWitness() and surrounding 
functions, and the code for emitting a protocol witness thunk (where you would 
actually apply the default arguments) is in lib/SILGen/SILGenPoly.cpp, 
emitProtocolWitness(). It would be a good not-quite-starter-project ;-)

Slava

> 
> - Dave Sweeris 
> ___
> 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


Re: [swift-evolution] Closures from methods with default args

2017-01-19 Thread David Sweeris via swift-evolution
> On Jan 20, 2017, at 00:09, David Sweeris via swift-evolution 
>  wrote:
> 
> 
>> On Jan 19, 2017, at 23:26, Xiaodi Wu  wrote:
>> 
>> Hmm, I don't recall the earlier discussion,
> It was a *long* time ago. I'll see if I can find it. If I'm misremembering, 
> then...
> 
>> but IMO, Charlie's proposal is pretty sensible. Seems backwards to adding 
>> much broader things like default argument support for protocols motivated by 
>> a use case that should Just Work(TM).
> Agreed, if it can be made to work.

Well I found the thread I was thinking of 
(https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160111/006795.html
 and 
https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160111/006798.html),
 and glancing over it, I was wrong. So... never mind about my reply to Charlie.

- Dave Sweeris ___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] Closures from methods with default args

2017-01-19 Thread Chris Lattner via swift-evolution
On Jan 19, 2017, at 9:26 PM, Xiaodi Wu via swift-evolution 
 wrote:
> 
> Hmm, I don't recall the earlier discussion, but IMO, Charlie's proposal is 
> pretty sensible. Seems backwards to adding much broader things like default 
> argument support for protocols motivated by a use case that should Just 
> Work(TM).
> 
> I recall that once upon a time Chris Lattner declared that the core team was 
> perfectly willing to implement difficult things if it improved the Swift user 
> experience. Here, it seems either this is something that *can* be made to 
> just work in the default arguments handling department, and then it should 
> be, or it can't, and then the closure syntax is a fairly obvious and workable 
> if not pretty workaround. No point in designing features as a workaround for 
> something that has both an obvious ideal solution and a current workaround.

Yeah, I agree with Xiaodi on this.  This is something that should “just work” 
and only fails due to implementation limitations.  In principle, we should make 
partial applications of methods (i.e. like "value.method(x:)”) be as similar to 
an explicit closure as is reasonable (e.g. “{ value.method(x: $0) }”).  This 
means that default arguments should work in this case.

-Chris


> On Thu, Jan 19, 2017 at 23:07 David Sweeris via swift-evolution 
> mailto:swift-evolution@swift.org>> wrote:
> 
> On Jan 9, 2017, at 02:13, Charlie Monroe via swift-evolution 
> 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.
> 
> 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 
> 
> ___
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

___
swift-evolu

Re: [swift-evolution] Closures from methods with default args

2017-01-19 Thread David Sweeris via swift-evolution

> On Jan 19, 2017, at 23:26, Xiaodi Wu  wrote:
> 
> Hmm, I don't recall the earlier discussion,
It was a *long* time ago. I'll see if I can find it. If I'm misremembering, 
then...

> but IMO, Charlie's proposal is pretty sensible. Seems backwards to adding 
> much broader things like default argument support for protocols motivated by 
> a use case that should Just Work(TM).
Agreed, if it can be made to work.

- Dave Sweeris
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] Closures from methods with default args

2017-01-19 Thread Xiaodi Wu via swift-evolution
Hmm, I don't recall the earlier discussion, but IMO, Charlie's proposal is
pretty sensible. Seems backwards to adding much broader things like default
argument support for protocols motivated by a use case that should Just
Work(TM).

I recall that once upon a time Chris Lattner declared that the core team
was perfectly willing to implement difficult things if it improved the
Swift user experience. Here, it seems either this is something that *can*
be made to just work in the default arguments handling department, and then
it should be, or it can't, and then the closure syntax is a fairly obvious
and workable if not pretty workaround. No point in designing features as a
workaround for something that has both an obvious ideal solution and a
current workaround.
On Thu, Jan 19, 2017 at 23:07 David Sweeris via swift-evolution <
swift-evolution@swift.org> wrote:

>
> On Jan 9, 2017, at 02:13, Charlie Monroe via swift-evolution <
> 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.
>
> 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
>
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] Closures from methods with default args

2017-01-19 Thread David Sweeris via swift-evolution

> On Jan 9, 2017, at 02:13, Charlie Monroe via swift-evolution 
>  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.

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


[swift-evolution] Closures from methods with default args

2017-01-19 Thread James Froggatt via swift-evolution
I'd also like to see a solution to this, FWIW.
Sometime's it's hard to tell whether something is its own function, or another 
function with with some defaulted parameters, so I could imagine this being a 
source of confusion.

> 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?
> 
> 
> 
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


[swift-evolution] Closures from methods with default args

2017-01-09 Thread Charlie Monroe via swift-evolution
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?___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution