[swift-users] Swift 3 (Xcode 8 GM) issue with @escaping

Shawn Erickson shawnce at gmail.com
Wed Sep 7 23:16:06 CDT 2016


I seem to have hit a possibly related @escaping issue...

The following code worked without issue under Swift 2.x and earlier
variants of Swift 3 but after the @escaping change (fairly sure that is
what is at fault) it no longer compiles.

protocol Foo {
    // Happy
    func visitValues<T>(visitors: [(key: String, body: (T) throws ->
Void)]) throws

    // Happy
    func visitValues<T>(throwOnWrongType: Bool, visitors: [(key: String,
body: (T) throws -> Void)]) throws
}

protocol FooBar { // IGNORE ME - NOT PART OF ORIGINAL CODE
    // Unhappy - this is appearntly expected given prior emails in this
thread
    // @escaping may only be applied to parameters of function type
    func visitValues<T>(visitors: [(key: String, body: @escaping (T) throws
-> Void)]) throws

    // Unhappy - this is appearntly expected given prior emails in this
thread
    // @escaping may only be applied to parameters of function type
    func visitValues<T>(throwOnWrongType: Bool, visitors: [(key: String,
body: @escaping (T) throws -> Void)]) throws
}

// Provide a default implementation for the simple visitor version
extension Foo {
    // Happy
    func visitValues<T>(visitors: [(String, body: (T) throws -> Void)])
throws {
        try self.visitValues(throwOnWrongType: false, visitors: visitors)
    }
}

// Unhappy
// error: type 'RealFoo' does not conform to protocol 'Foo'
struct RealFoo : Foo {
    // Happy
    func visitValues<T>(throwOnWrongType: Bool, visitors: [(key: String,
body: (T) throws -> Void)]) throws {
        // do stuff...
    }

    // error: MyPlayground.playground:23:8: error: type 'RealFoo' does not
conform to protocol 'Foo'
    //struct RealFoo : Foo {
    //    ^
    //
    //    MyPlayground.playground:16:10: note: candidate has non-matching
type '<Self, T> (visitors: [(String, body: (T) throws -> Void)]) throws ->
()' (aka '<τ_0_0, τ_1_0> (visitors: Array<(String, body: (τ_1_0) throws ->
())>) throws -> ()')
    //    func visitValues<T>(visitors: [(String, body: (T) throws ->
Void)]) throws {

    // The fix-it suggestion for "error: type 'RealFoo' does not conform to
protocol 'Foo'" inserts the following which makes
    // the "not conform" error go away however it doesn't compile because
of @escaping
    // Unhappy
    // @escaping may only be applied to parameters of function type
    internal func visitValues<T>(visitors: [(key: String, body: @escaping
(T) throws -> Void)]) throws { // NOT PART OF ORIGINAL CODE
    }
    // The above shouldn't be needed since an implementation is provided
via an extension on protocol Foo right?
}

On Wed, Sep 7, 2016 at 8:06 PM Shawn Erickson <shawnce at gmail.com> wrote:

> To more completely state what I find it a little strange.
>
> The default was moved to be non-escaping since that is the better default
> (for various reason) with @escaping being used to both inform the compiler
> that something is intentionally escaping (yeah I meant to do that) and to
> me it seem also helpful as a way to inform the user of the API that the
> closure they are providing is escaping so they better understand the
> requirements placed on that closure (e.g. it may not be called before the
> called function returns, possible retain cycle issues, etc.).
>
> So when using APIs I would look for @escaping as a way to know I need to
> think a little more about the behavior of the closure and the func taking
> the closure that I am calling. If I don't see it I may incorrectly assume
> it isn't escaping when intact it may have be implicitly escaping.
>
> Anyway my thoughts on this...
>
> -Shawn
>
>
>
> On Wed, Sep 7, 2016 at 7:08 PM Shawn Erickson <shawnce at gmail.com> wrote:
>
>> It just seems a little strange that @escaping only shows up once in the
>> following example (real) function of mine yet both of them are escaping.
>> This fixit message should maybe imply that @escaping isn't needed since the
>> optional one is already implicitly considered escaping? ...it is kinda
>> confusing when first jumping over to Swift if at one point you are told you
>> need to added @escaping (the non-optional one) yet you are told @escaping
>> isn't valid for the optional one despite it needing to be escaping (e.g.
>> the fixit doesn't really explain that is already escaping).
>>
>>     func httpGet<T>(path: String, parameters: [String:String] = [:],
>>                     needsAuth: Bool = true, queue: DispatchQueue =
>> DispatchQueue.main,
>>                     completion: ObjectFetchCallback<T>?, importer:
>> @escaping HttpImporterCallback<T>)
>>
>> -Shawn
>>
>> On Wed, Sep 7, 2016 at 6:51 PM Jacob Bandes-Storch <jtbandes at gmail.com>
>> wrote:
>>
>>> On Wed, Sep 7, 2016 at 5:54 PM, Michael Ilseman via swift-users <
>>> swift-users at swift.org> wrote:
>>>
>>>> I implemented a better (i.e. correct) diagnostic message for this at
>>>> https://github.com/apple/swift/pull/4670. I want to also do a better
>>>> diagnostic specifically for aggregate parameters to functions (e.g.
>>>> optional closures), but that requires more work in the type checker.
>>>>
>>>> Basically, @escaping is valid only on closures in function parameter
>>>> position. The noescape-by-default rule only applies to these closures at
>>>> function parameter position, otherwise they are escaping. Aggregates, such
>>>> as enums with associated values (e.g. Optional), tuples, structs, etc., if
>>>> they have closures, follow the default rules for closures that are not at
>>>> function parameter position, i.e. they are escaping.
>>>>
>>>
>>> Shouldn't it be possible to allow distinguishing @escaping/@noescape for
>>> aggregates like these, at least for the simple case of Optional?  (I
>>> handled optionals in https://github.com/apple/swift/pull/4438 for
>>> imported function types; see comment
>>> <https://github.com/apple/swift/pull/4438#issuecomment-243645367>.)
>>>
>>>
>>>>
>>>> It would be a post-Swift-3 addition to the language to be able to
>>>> support more robust liveness tracking here. There may be interesting
>>>> directions to take this, with optional closures being the most common
>>>> beneficiary.
>>>>
>>>> On Sep 7, 2016, at 3:33 PM, Shawn Erickson via swift-users <
>>>> swift-users at swift.org> wrote:
>>>>
>>>> I see https://bugs.swift.org/browse/SR-2324 and
>>>> https://bugs.swift.org/browse/SR-2444 which looks related to this
>>>> issue and may explain the error I saw on "the other side" of this.
>>>>
>>>>
>>>>
>>>> On Wed, Sep 7, 2016 at 3:28 PM Shawn Erickson <shawnce at gmail.com>
>>>> wrote:
>>>>
>>>>> Yeah I actually have a few of those myself that I can no longer do.
>>>>>
>>>>> On Wed, Sep 7, 2016 at 3:26 PM Jon Shier <jon at jonshier.com> wrote:
>>>>>
>>>>>> Perhaps relatedly, it no longer seems possible to mark typealiased
>>>>>> closures as @escaping. That was quite handy when you know that closures
>>>>>> will always be used asynchronously.
>>>>>>
>>>>>>
>>>>>> Jon
>>>>>>
>>>>>>
>>>>>> On Sep 7, 2016, at 6:15 PM, Shawn Erickson via swift-users <
>>>>>> swift-users at swift.org> wrote:
>>>>>>
>>>>>> I should note that this issue also appeared in an earlier variant of
>>>>>> Swift after the addition of @escaping but I was on vacation so didn't get a
>>>>>> chance to report it then. It isn't new with the Xcode 8 GM.
>>>>>>
>>>>>> On Wed, Sep 7, 2016 at 3:08 PM Shawn Erickson <shawnce at gmail.com>
>>>>>> wrote:
>>>>>>
>>>>>>> I like and fully supported the change to @escaping away from
>>>>>>> @noescape however in a body of code that I am porting to the latest Swift 3
>>>>>>> variant (as found in Xcode 8 GM) I am hitting an issue for methods that
>>>>>>> take an optional completion closure. If optional is involved I can't find a
>>>>>>> way to apply @escape to the escaping closure. See the following for an
>>>>>>> basic example...
>>>>>>>
>>>>>>> Is their a way to do what I need and/or is this an edge case in the
>>>>>>> implementation of @escaping?
>>>>>>>
>>>>>>> typealias MyCallback = (String)->()
>>>>>>>
>>>>>>> // Happy
>>>>>>> func foo1(bar: String, completion: ((String)->())) {
>>>>>>>     completion(bar)
>>>>>>> }
>>>>>>>
>>>>>>> // Happy
>>>>>>> func foo2(bar: String, completion: MyCallback) {
>>>>>>>     completion(bar)
>>>>>>> }
>>>>>>>
>>>>>>> // Happy
>>>>>>> func foo3(bar: String, completion: ((String)->())? = nil) {
>>>>>>>     completion?(bar)
>>>>>>> }
>>>>>>>
>>>>>>> // Happy
>>>>>>> func foo4(bar: String, completion: MyCallback? = nil) {
>>>>>>>     completion?(bar)
>>>>>>> }
>>>>>>>
>>>>>>> // Happy
>>>>>>> func foo5(bar: String, completion: Optional<MyCallback> = nil) {
>>>>>>>     completion?(bar)
>>>>>>> }
>>>>>>>
>>>>>>> // Happy
>>>>>>> func foo6(bar: String, completion: @escaping (String)->()) {
>>>>>>>     completion(bar)
>>>>>>> }
>>>>>>>
>>>>>>> // Happy
>>>>>>> func foo7(bar: String, completion: @escaping MyCallback) {
>>>>>>>     completion(bar)
>>>>>>> }
>>>>>>>
>>>>>>> // Unhappy...
>>>>>>> // "@escaping attribute only applies to function types"
>>>>>>> func foo8(bar: String, completion: @escaping ((String)->())? = nil) {
>>>>>>>     completion?(bar)
>>>>>>> }
>>>>>>>
>>>>>>> // Unhappy...
>>>>>>> // "@escaping attribute only applies to function types"
>>>>>>> func foo9(bar: String, completion: @escaping MyCallback? = nil) {
>>>>>>>     completion?(bar)
>>>>>>> }
>>>>>>>
>>>>>>> // Unhappy...
>>>>>>> // "@escaping attribute only applies to function types"
>>>>>>> func foo10(bar: String, completion: (@escaping ((String)->()))? =
>>>>>>> nil) {
>>>>>>>     completion?(bar)
>>>>>>> }
>>>>>>>
>>>>>>> // Unhappy...
>>>>>>> // "@escaping attribute only applies to function types"
>>>>>>> func foo11(bar: String, completion: (@escaping MyCallback)? = nil) {
>>>>>>>     completion?(bar)
>>>>>>> }
>>>>>>>
>>>>>>> // Unhappy...
>>>>>>> // "@escaping attribute only applies to function types"
>>>>>>> func foo12(bar: String, completion: Optional<@escaping MyCallback> =
>>>>>>> nil) {
>>>>>>>     completion?(bar)
>>>>>>> }
>>>>>>>
>>>>>> _______________________________________________
>>>>>> swift-users mailing list
>>>>>> swift-users at swift.org
>>>>>> https://lists.swift.org/mailman/listinfo/swift-users
>>>>>>
>>>>>>
>>>>>> _______________________________________________
>>>> swift-users mailing list
>>>> swift-users at swift.org
>>>> https://lists.swift.org/mailman/listinfo/swift-users
>>>>
>>>>
>>>>
>>>> _______________________________________________
>>>> swift-users mailing list
>>>> swift-users at swift.org
>>>> https://lists.swift.org/mailman/listinfo/swift-users
>>>>
>>>>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-users/attachments/20160908/3d068387/attachment.html>


More information about the swift-users mailing list