Thanks for your input Michael,

You're right that argument modifiers should go before the argument, and type 
qualifiers before the type:

        func f(@once closure: @noescape () -> ())

Since @once actually implies @noescape (as described earlier in the thread), it 
can be shortened to:

        func f(@once closure: () -> ()) // implicit @noescape

> Or maybe it's just because I can't think of a realistic use case for using 
> "@noescape(once)".

The use case is the following: @once closures let the compiler know that the 
closure code is executed. It allows declaration of undefined `let` variables 
that are initialized in the @once closure:

        let x: Int
        f { x = 1 }
        // use x

Without @once, the developer has to work around:

        var x: Int = 0 // two problems: `var` declaration, and dummy value
        f { x = 1 }
        // use x

If this proposal would be accepted, the next step would be to ask for 
dispatch_sync functions et al. to use this qualifier (as well as other standard 
functions like autoreleasepool, withUnsafeBufferPointer, etc.):

        let x: Int
        dispatch_sync(queue) {
                x = 1
        }

And now high-level objects that use internal queues are easier to use:

        let items: [Item]
        let users: [User]
        dbQueue.inDatabase { db in
                items = Item.fetchAll(db)
                users = User.fetchAll(db)
        }

This pattern would greatly improve many libraries, and my own 
http://github.com/groue/GRDB.swift in particular.

Gwendal Roué


> Le 23 avr. 2016 à 14:16, Michael Peternell <[email protected]> a écrit 
> :
> 
> Hi Gwendal,
> 
>> Am 23.04.2016 um 12:18 schrieb Gwendal Roué via swift-evolution 
>> <[email protected]>:
>> 
>> Hello Andrew,
>> 
>> I'm rather embarrassed: the initial design of this proposal was based on a 
>> modifier of @noescape:
>> 
>>      func f(@noescape(once) closure: () -> ()) { … }
>> 
>> But since the 0049 proposal has been accepted 
>> (https://github.com/apple/swift-evolution/blob/master/proposals/0049-noescape-autoclosure-type-attrs.md),
>>  @noescape is no longer an argument qualifier, but a type attribute.
> 
> maybe I cannot give competent advice from the language designers perspective, 
> but I can speak as a language user.
> 
> I think it is more intuitive to have the name of the argument first: 
> "ARGUMENT-NAME: NOESCAPE AUTOCLOSURE TYPE FOOBAR-QUALIFIER..., 
> NEXT-ARGUMENT-NAME..." and not "SOME-MODIFIERS-FIRST ARGUMENT-NAME: 
> SOME-MODIFIERS-LAST". I think the old behavior reminded me too much of C, 
> where the argument name is at some arbitrary place, surrounded by type names, 
> parens, and whatnot; "void foo(int __cdecl (*bar)(int foobar, void 
> *context))" where "bar" is the argument name, the first "int" is the return 
> type of the "bar" function, "int" and "void*" are the two argument types, and 
> "__cdecl" is the calling convention of the "bar" function.
> 
> And about @noescape(once)... Would it not work anymore? I know it's not part 
> of the current SE-0049 proposal, but I can't see why it couldn't be expanded 
> to include `once`. Or maybe it's just because I can't think of a realistic 
> use case for using "@noescape(once)".
> 
>> The `once` discussed here can not be part of the type: if noescape can 
>> understandably be part of the type, the fact that a function guarantees it 
>> will call a closure once is a quality of that function, not of the closure.
> 
> Yes it is a quality of the function and not of the type. But why not just 
> leave it at that place and just call it "argument qualifier"? Or maybe the 
> general layout changed? In Swift 2 it was "ARGUMENT_QUALIFIERS ARGUMENT_NAME: 
> TYPE_ATTRIBUTES TYPE", and in Swift 3 it is "ARGUMENT_NAME: 
> ARGUMENT_QUALIFIERS TYPE_ATTRIBUTES TYPE"?
> 
>> So the proposed @noescape(once) syntax is now confusing as it would mix a 
>> type attribute and a argument qualifier.
>> 
>> I don't quite know how to escape this:
>> 
>>      // two @ signs
>>      func f(@noescape @once closure: () -> ()) { … }
>> 
>>      // Implies @noescape
>>      func f(@once closure: () -> ()) { … }
> 
> How about
> 
>    func f(closure: @noescape(once) () -> ()) { ... }
> 
> -Michael
> 
>> 
>> I'd like advice from competent people before I would attempt a rewrite of 
>> the proposal.
>> 
>> Gwendal Roué
>> 
>>> Le 10 avr. 2016 à 23:26, Andrew Bennett <[email protected]> a écrit :
>>> 
>>> Sorry I missed that scrolling back through the history, that proposal looks 
>>> great. It doesn't look like it has been submitted as a pull request to 
>>> swift-evolution yet though.
>>> 
>>> On Sunday, 10 April 2016, Gwendal Roué <[email protected]> wrote:
>>> Felix Cloutier already wrote one: 
>>> https://github.com/zneak/swift-evolution/blob/master/proposals/00xx-noescape-once.md
>>> 
>>> Do you think it needs to be rewritten?
>>> 
>>> Gwendal Roué
>>> 
>>>> Le 10 avr. 2016 à 14:56, Andrew Bennett <[email protected]> a écrit :
>>>> 
>>>> Hi, not beyond this thread that I have seen. I think it's worth you 
>>>> summarizing this thread in a formal proposal and putting it up for 
>>>> discussion or submitting it as a PR :)
>>>> 
>>>> On Sunday, 10 April 2016, Gwendal Roué <[email protected]> wrote:
>>>> Hello all,
>>>> 
>>>> I was wondering if this topic had evolved in anyway since its original 
>>>> introduction.
>>>> 
>>>> @noescape(once) would still be a useful addition to the language!
>>>> 
>>>> Gwendal Roué
>>>> 
>>>> 
>>>> 
>>>>> Le 3 févr. 2016 à 22:21, Félix Cloutier via swift-evolution 
>>>>> <[email protected]> a écrit :
>>>>> 
>>>>> I updated the proposal to address some concerns. It can be found at: 
>>>>> https://github.com/zneak/swift-evolution/blob/master/proposals/00xx-noescape-once.md
>>>>> 
>>>>> Things that changed:
>>>>> 
>>>>>   • It now says that the closure must be called on code paths where the 
>>>>> function throws;
>>>>>   • you can have multiple @noescape(once) parameters but they can't make 
>>>>> assumptions from one another.
>>>>> 
>>>>> I'm not 100% convinced that forcing a call on code paths that throw is 
>>>>> always desirable. I've changed it because Chris's support probably means 
>>>>> that the feature has better chances of making it, but I'm not convinced 
>>>>> yet. If throwing allows me to return without calling the closure, I can 
>>>>> write this:
>>>>> 
>>>>> do {
>>>>>   let foo: Int
>>>>>   try withLock(someLock, timeout: 0.5) {
>>>>>           foo = sharedThing.foo
>>>>>   }
>>>>> } catch {
>>>>>   print("couldn't acquire lock fast enough")
>>>>> }
>>>>> 
>>>>> which would be kind of messy if instead, the closure needed a parameter 
>>>>> to tell whether the lock was acquired or not when it runs.
>>>>> 
>>>>> Félix
>>>>> 
>>>>> _______________________________________________
>>>>> swift-evolution mailing list
>>>>> [email protected]
>>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>> 
>>> 
>> 
>> _______________________________________________
>> swift-evolution mailing list
>> [email protected]
>> https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to