Code blocks and trailing closures


(Rien) #1

What does the following code fragment do?

serverCert.write(to: certificateUrl) { showErrorInKeyWindow(message); return }

The only possible answer is: I don’t know.

The problem is finding out what the “return” statement will do.

Without knowing if the {...} is a code block or a trailing closure it is impossible to know what the return statement will do. It will either end the closure or it will end the function that contains this code block.

This could be disambiguated by using the same syntax as for lazy variables:

serverCert.write(to: serverCertificateUrl) { showErrorInKeyWindow(message: message); return }()

Now it is clear that the return statement will only terminate the (trailing) closure.

A question to the educators on the list: Is this a real problem?

Personally, I dislike this situation, but I am also ambivalent towards the solution I just described.

Regards,
Rien

Site: http://balancingrock.nl
Blog: http://swiftrien.blogspot.com
Github: http://github.com/Balancingrock
Project: http://swiftfire.nl


(Adrian Zubarev) #2

I’m slightly confused by this. How is a trailing closure different from a code block in Swift? It’s basically the same thing with some extra syntax sugar because it happens to be the last parameter of your function.

You can simply write this if you wanted to:

myFucntion(someLabel: abc, closureLabel: { …; return })
Parentheses are indicating that your closure is immediately invoked.

let someInt = { return 42 }()
print(someInt)

let someClosureWhichReturnsAnInt = { return 42 } // You can reuse the closure
print(someClosureWhichReturnsAnInt()) // Invocation happens now here
return is scope based and it’s totally clear (to me) that in your case return will return from your closure with a value of Void.

···

--
Adrian Zubarev
Sent with Airmail

Am 15. März 2017 um 11:35:39, Rien via swift-evolution (swift-evolution@swift.org) schrieb:

What does the following code fragment do?

serverCert.write(to: certificateUrl) { showErrorInKeyWindow(message); return }

The only possible answer is: I don’t know.

The problem is finding out what the “return” statement will do.

Without knowing if the {...} is a code block or a trailing closure it is impossible to know what the return statement will do. It will either end the closure or it will end the function that contains this code block.

This could be disambiguated by using the same syntax as for lazy variables:

serverCert.write(to: serverCertificateUrl) { showErrorInKeyWindow(message: message); return }()

Now it is clear that the return statement will only terminate the (trailing) closure.

A question to the educators on the list: Is this a real problem?

Personally, I dislike this situation, but I am also ambivalent towards the solution I just described.

Regards,
Rien

Site: http://balancingrock.nl
Blog: http://swiftrien.blogspot.com
Github: http://github.com/Balancingrock
Project: http://swiftfire.nl

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Nick Keets) #3

I think the word you are looking for is “confusing”, not “ambiguous”.
Nothing is ambiguous
about the code you wrote, but you could make an argument that you find it
confusing (since this is something subjective).

···

On Wed, Mar 15, 2017 at 12:35 PM, Rien via swift-evolution < swift-evolution@swift.org> wrote:

What does the following code fragment do?

serverCert.write(to: certificateUrl) { showErrorInKeyWindow(message);
return }

The only possible answer is: I don’t know.

The problem is finding out what the “return” statement will do.

Without knowing if the {...} is a code block or a trailing closure it is
impossible to know what the return statement will do. It will either end
the closure or it will end the function that contains this code block.

This could be disambiguated by using the same syntax as for lazy variables:

serverCert.write(to: serverCertificateUrl) { showErrorInKeyWindow(message:
message); return }()

Now it is clear that the return statement will only terminate the
(trailing) closure.

A question to the educators on the list: Is this a real problem?

Personally, I dislike this situation, but I am also ambivalent towards the
solution I just described.

Regards,
Rien

Site: http://balancingrock.nl
Blog: http://swiftrien.blogspot.com
Github: http://github.com/Balancingrock
Project: http://swiftfire.nl

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Kenny Leung) #4

I have proposed that a different keyword be used to return out of blocks. In Objective-C, I have a #define that aliases “blockreturn” and I use that exclusively in breaking out of blocks.

-Kenny

···

On Mar 15, 2017, at 3:35 AM, Rien via swift-evolution <swift-evolution@swift.org> wrote:

What does the following code fragment do?

serverCert.write(to: certificateUrl) { showErrorInKeyWindow(message); return }

The only possible answer is: I don’t know.

The problem is finding out what the “return” statement will do.

Without knowing if the {...} is a code block or a trailing closure it is impossible to know what the return statement will do. It will either end the closure or it will end the function that contains this code block.

This could be disambiguated by using the same syntax as for lazy variables:

serverCert.write(to: serverCertificateUrl) { showErrorInKeyWindow(message: message); return }()

Now it is clear that the return statement will only terminate the (trailing) closure.

A question to the educators on the list: Is this a real problem?

Personally, I dislike this situation, but I am also ambivalent towards the solution I just described.

Regards,
Rien

Site: http://balancingrock.nl
Blog: http://swiftrien.blogspot.com
Github: http://github.com/Balancingrock
Project: http://swiftfire.nl

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Slava Pestov) #5

What does the following code fragment do?

serverCert.write(to: certificateUrl) { showErrorInKeyWindow(message); return }

The only possible answer is: I don’t know.

No, that is incorrect.

The code block in question is either a training closure argument to serverCert.write(), or it is a syntax error.

We don’t allow ‘naked’ blocks in Swift. If you want to evaluate a closure and discard it, you have to use ‘_ =‘:

_ = { … }

If you want to just introduce a new lexical scope you have to use the ‘do’ keyword:

do {
  stuff
  return
}

The problem is finding out what the “return” statement will do.

Without knowing if the {...} is a code block or a trailing closure it is impossible to know what the return statement will do. It will either end the closure or it will end the function that contains this code block.

This could be disambiguated by using the same syntax as for lazy variables:

There’s no special syntax for lazy variables, this is just a trick for turning a statement into an expression. It works with non-lazy vars too:

var x = { some statement; return x }()

Slava

···

On Mar 15, 2017, at 3:35 AM, Rien via swift-evolution <swift-evolution@swift.org> wrote:

serverCert.write(to: serverCertificateUrl) { showErrorInKeyWindow(message: message); return }()

Now it is clear that the return statement will only terminate the (trailing) closure.

A question to the educators on the list: Is this a real problem?

Personally, I dislike this situation, but I am also ambivalent towards the solution I just described.

Regards,
Rien

Site: http://balancingrock.nl
Blog: http://swiftrien.blogspot.com
Github: http://github.com/Balancingrock
Project: http://swiftfire.nl

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Rien) #6

If I wrote this:

if serverCert.write(to: certificateUrl) { showErrorInKeyWindow(message); return }

then the meaning of return would have been different.

Imo it is a problem that two pieces of code impact the understanding of each other and that those two pieces of code could potentially be very far apart.

I do agree that the parenthesis are not a perfect solution, it was just the first thing that I could think of and that has some level of similarity in meaning.

Regards,
Rien

Site: http://balancingrock.nl
Blog: http://swiftrien.blogspot.com
Github: http://github.com/Balancingrock
Project: http://swiftfire.nl

···

On 15 Mar 2017, at 12:00, Adrian Zubarev <adrian.zubarev@devandartist.com> wrote:

I’m slightly confused by this. How is a trailing closure different from a code block in Swift? It’s basically the same thing with some extra syntax sugar because it happens to be the last parameter of your function.

You can simply write this if you wanted to:

myFucntion(someLabel: abc, closureLabel: { …; return })

Parentheses are indicating that your closure is immediately invoked.

let someInt = { return 42 }()
print(someInt)

let someClosureWhichReturnsAnInt = { return 42 } // You can reuse the closure
print(someClosureWhichReturnsAnInt()) // Invocation happens now here

return is scope based and it’s totally clear (to me) that in your case return will return from your closure with a value of Void.

--
Adrian Zubarev
Sent with Airmail

Am 15. März 2017 um 11:35:39, Rien via swift-evolution (swift-evolution@swift.org) schrieb:

What does the following code fragment do?

serverCert.write(to: certificateUrl) { showErrorInKeyWindow(message); return }

The only possible answer is: I don’t know.

The problem is finding out what the “return” statement will do.

Without knowing if the {...} is a code block or a trailing closure it is impossible to know what the return statement will do. It will either end the closure or it will end the function that contains this code block.

This could be disambiguated by using the same syntax as for lazy variables:

serverCert.write(to: serverCertificateUrl) { showErrorInKeyWindow(message: message); return }()

Now it is clear that the return statement will only terminate the (trailing) closure.

A question to the educators on the list: Is this a real problem?

Personally, I dislike this situation, but I am also ambivalent towards the solution I just described.

Regards,
Rien

Site: http://balancingrock.nl
Blog: http://swiftrien.blogspot.com
Github: http://github.com/Balancingrock
Project: http://swiftfire.nl

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Rien) #7

I think the word you are looking for is “confusing”, not “ambiguous”. Nothing is ambiguous
about the code you wrote, but you could make an argument that you find it confusing (since this is something subjective).

Agreed.

Rien.

···

On 15 Mar 2017, at 13:33, Nick Keets <nick.keets@gmail.com> wrote:

On Wed, Mar 15, 2017 at 12:35 PM, Rien via swift-evolution <swift-evolution@swift.org> wrote:
What does the following code fragment do?

serverCert.write(to: certificateUrl) { showErrorInKeyWindow(message); return }

The only possible answer is: I don’t know.

The problem is finding out what the “return” statement will do.

Without knowing if the {...} is a code block or a trailing closure it is impossible to know what the return statement will do. It will either end the closure or it will end the function that contains this code block.

This could be disambiguated by using the same syntax as for lazy variables:

serverCert.write(to: serverCertificateUrl) { showErrorInKeyWindow(message: message); return }()

Now it is clear that the return statement will only terminate the (trailing) closure.

A question to the educators on the list: Is this a real problem?

Personally, I dislike this situation, but I am also ambivalent towards the solution I just described.

Regards,
Rien

Site: http://balancingrock.nl
Blog: http://swiftrien.blogspot.com
Github: http://github.com/Balancingrock
Project: http://swiftfire.nl

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Rick M) #8

I actually don't like this situation, either. I find it gets a bit confusing to know what's a block and what's just nested scope. I, too, have had an impulse to have a different keyword for returning from a block, but what I really want is for the entire scope of the block to be called out differently.

This is true regardless of whether or not it's a trailing closure.

I wonder if the source editor (e.g. Xcode) could draw three sides of a box with arrows:

    { <--------------------+
        some code |
        more code |
    } <--------------------+

I don't know if this would quickly get messy and distracting. It would be challenging to find exactly the right way to draw it that pleases everyone (it should, obviously, be hyper-customizable, but Apple hates settings), and to draw it to make it easy to see what it's pointing to without trampling over end-of-line comments.

Maybe subtle highlighting of the background (all the way across the window) to show block, but that makes it harder to show nested blocks.

···

On Mar 19, 2017, at 20:33 , Kenny Leung via swift-evolution <swift-evolution@swift.org> wrote:

I have proposed that a different keyword be used to return out of blocks. In Objective-C, I have a #define that aliases “blockreturn” and I use that exclusively in breaking out of blocks.

-Kenny

On Mar 15, 2017, at 3:35 AM, Rien via swift-evolution <swift-evolution@swift.org> wrote:

What does the following code fragment do?

serverCert.write(to: certificateUrl) { showErrorInKeyWindow(message); return }

The only possible answer is: I don’t know.

The problem is finding out what the “return” statement will do.

Without knowing if the {...} is a code block or a trailing closure it is impossible to know what the return statement will do. It will either end the closure or it will end the function that contains this code block.

This could be disambiguated by using the same syntax as for lazy variables:

serverCert.write(to: serverCertificateUrl) { showErrorInKeyWindow(message: message); return }()

Now it is clear that the return statement will only terminate the (trailing) closure.

A question to the educators on the list: Is this a real problem?

Personally, I dislike this situation, but I am also ambivalent towards the solution I just described.

Regards,
Rien

Site: http://balancingrock.nl
Blog: http://swiftrien.blogspot.com
Github: http://github.com/Balancingrock
Project: http://swiftfire.nl

_______________________________________________
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

--
Rick Mann
rmann@latencyzero.com


(Adrian Zubarev) #9

There is no if … on my screen nor there is one here https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon–20170313/033888.html. May be a typo?

In that case it cannot be a trailing closure because trailing closures are banned in such scenarios. https://github.com/apple/swift-evolution/blob/master/proposals/0056-trailing-closures-in-guard.md

As for the lazy variables you’ve mentioned in the original posts, the closure there is invoked lately but only once and it cannot be reused at all.

Let me know if I understood your gist now.

if someFunction { …; return } // someFunction cannot have a trailing closure here!

···

--
Adrian Zubarev
Sent with Airmail

Am 15. März 2017 um 12:08:19, Rien (rien@balancingrock.nl) schrieb:

If I wrote this:

if serverCert.write(to: certificateUrl) { showErrorInKeyWindow(message); return }

then the meaning of return would have been different.

Imo it is a problem that two pieces of code impact the understanding of each other and that those two pieces of code could potentially be very far apart.

I do agree that the parenthesis are not a perfect solution, it was just the first thing that I could think of and that has some level of similarity in meaning.

Regards,
Rien

Site: http://balancingrock.nl
Blog: http://swiftrien.blogspot.com
Github: http://github.com/Balancingrock
Project: http://swiftfire.nl

On 15 Mar 2017, at 12:00, Adrian Zubarev <adrian.zubarev@devandartist.com> wrote:

I’m slightly confused by this. How is a trailing closure different from a code block in Swift? It’s basically the same thing with some extra syntax sugar because it happens to be the last parameter of your function.

You can simply write this if you wanted to:

myFucntion(someLabel: abc, closureLabel: { …; return })

Parentheses are indicating that your closure is immediately invoked.

let someInt = { return 42 }()
print(someInt)

let someClosureWhichReturnsAnInt = { return 42 } // You can reuse the closure
print(someClosureWhichReturnsAnInt()) // Invocation happens now here

return is scope based and it’s totally clear (to me) that in your case return will return from your closure with a value of Void.

--
Adrian Zubarev
Sent with Airmail

Am 15. März 2017 um 11:35:39, Rien via swift-evolution (swift-evolution@swift.org) schrieb:

What does the following code fragment do?

serverCert.write(to: certificateUrl) { showErrorInKeyWindow(message); return }

The only possible answer is: I don’t know.

The problem is finding out what the “return” statement will do.

Without knowing if the {...} is a code block or a trailing closure it is impossible to know what the return statement will do. It will either end the closure or it will end the function that contains this code block.

This could be disambiguated by using the same syntax as for lazy variables:

serverCert.write(to: serverCertificateUrl) { showErrorInKeyWindow(message: message); return }()

Now it is clear that the return statement will only terminate the (trailing) closure.

A question to the educators on the list: Is this a real problem?

Personally, I dislike this situation, but I am also ambivalent towards the solution I just described.

Regards,
Rien

Site: http://balancingrock.nl
Blog: http://swiftrien.blogspot.com
Github: http://github.com/Balancingrock
Project: http://swiftfire.nl

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(David Rönnqvist) #10

Xcode can already draw boxes for nesting scopes, but it’s disabled by default. You’ll find it under: Editor > Code Folding > Focus Follows Selection.

That said, IIRC it’s been mentioned on this list that (I’m paraphrasing) we should try and avoid designs that rely on editor functionality, and also that a Xcode is independent from the mailing list.

···

On 20 Mar 2017, at 07:22, Rick Mann via swift-evolution <swift-evolution@swift.org> wrote:

I actually don't like this situation, either. I find it gets a bit confusing to know what's a block and what's just nested scope. I, too, have had an impulse to have a different keyword for returning from a block, but what I really want is for the entire scope of the block to be called out differently.

This is true regardless of whether or not it's a trailing closure.

I wonder if the source editor (e.g. Xcode) could draw three sides of a box with arrows:

   { <--------------------+
       some code |
       more code |
   } <--------------------+

I don't know if this would quickly get messy and distracting. It would be challenging to find exactly the right way to draw it that pleases everyone (it should, obviously, be hyper-customizable, but Apple hates settings), and to draw it to make it easy to see what it's pointing to without trampling over end-of-line comments.

Maybe subtle highlighting of the background (all the way across the window) to show block, but that makes it harder to show nested blocks.

On Mar 19, 2017, at 20:33 , Kenny Leung via swift-evolution <swift-evolution@swift.org> wrote:

I have proposed that a different keyword be used to return out of blocks. In Objective-C, I have a #define that aliases “blockreturn” and I use that exclusively in breaking out of blocks.

-Kenny

On Mar 15, 2017, at 3:35 AM, Rien via swift-evolution <swift-evolution@swift.org> wrote:

What does the following code fragment do?

serverCert.write(to: certificateUrl) { showErrorInKeyWindow(message); return }

The only possible answer is: I don’t know.

The problem is finding out what the “return” statement will do.

Without knowing if the {...} is a code block or a trailing closure it is impossible to know what the return statement will do. It will either end the closure or it will end the function that contains this code block.

This could be disambiguated by using the same syntax as for lazy variables:

serverCert.write(to: serverCertificateUrl) { showErrorInKeyWindow(message: message); return }()

Now it is clear that the return statement will only terminate the (trailing) closure.

A question to the educators on the list: Is this a real problem?

Personally, I dislike this situation, but I am also ambivalent towards the solution I just described.

Regards,
Rien

Site: http://balancingrock.nl
Blog: http://swiftrien.blogspot.com
Github: http://github.com/Balancingrock
Project: http://swiftfire.nl

_______________________________________________
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

--
Rick Mann
rmann@latencyzero.com

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Rien) #11

Sorry, it seems we are talking past each other, let me try again:

I left the “if” out on purpose. To show that even though the snippet was “valid” code, it was in fact ambiguous.

With closures (and autoclosures) it becomes possible -to some extent- to “enhance” the language.

Consider:

guard let c = somefunc() else { showError(); return }
myguard( let c = somefunc()) { showError(); return }

In this simple example it is clear that the second return behaves quite differently from the first.
It gets more difficult if the code in the block cq closure gets very large.
Also, I would expect that beginners would have problems understanding this (subtile but important) difference.

Regards,
Rien

Site: http://balancingrock.nl
Blog: http://swiftrien.blogspot.com
Github: http://github.com/Balancingrock
Project: http://swiftfire.nl

···

On 15 Mar 2017, at 12:19, Adrian Zubarev <adrian.zubarev@devandartist.com> wrote:

There is no if … on my screen nor there is one here https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon–20170313/033888.html. May be a typo?

In that case it cannot be a trailing closure because trailing closures are banned in such scenarios. https://github.com/apple/swift-evolution/blob/master/proposals/0056-trailing-closures-in-guard.md

As for the lazy variables you’ve mentioned in the original posts, the closure there is invoked lately but only once and it cannot be reused at all.

Let me know if I understood your gist now.

if someFunction { …; return } // someFunction cannot have a trailing closure here!

--
Adrian Zubarev
Sent with Airmail

Am 15. März 2017 um 12:08:19, Rien (rien@balancingrock.nl) schrieb:

If I wrote this:

if serverCert.write(to: certificateUrl) { showErrorInKeyWindow(message); return }

then the meaning of return would have been different.

Imo it is a problem that two pieces of code impact the understanding of each other and that those two pieces of code could potentially be very far apart.

I do agree that the parenthesis are not a perfect solution, it was just the first thing that I could think of and that has some level of similarity in meaning.

Regards,
Rien

Site: http://balancingrock.nl
Blog: http://swiftrien.blogspot.com
Github: http://github.com/Balancingrock
Project: http://swiftfire.nl

> On 15 Mar 2017, at 12:00, Adrian Zubarev <adrian.zubarev@devandartist.com> wrote:
>
> I’m slightly confused by this. How is a trailing closure different from a code block in Swift? It’s basically the same thing with some extra syntax sugar because it happens to be the last parameter of your function.
>
> You can simply write this if you wanted to:
>
> myFucntion(someLabel: abc, closureLabel: { …; return })
>
> Parentheses are indicating that your closure is immediately invoked.
>
> let someInt = { return 42 }()
> print(someInt)
>
> let someClosureWhichReturnsAnInt = { return 42 } // You can reuse the closure
> print(someClosureWhichReturnsAnInt()) // Invocation happens now here
>
> return is scope based and it’s totally clear (to me) that in your case return will return from your closure with a value of Void.
>
>
>
>
> --
> Adrian Zubarev
> Sent with Airmail
>
> Am 15. März 2017 um 11:35:39, Rien via swift-evolution (swift-evolution@swift.org) schrieb:
>
>> What does the following code fragment do?
>>
>> serverCert.write(to: certificateUrl) { showErrorInKeyWindow(message); return }
>>
>> The only possible answer is: I don’t know.
>>
>> The problem is finding out what the “return” statement will do.
>>
>> Without knowing if the {...} is a code block or a trailing closure it is impossible to know what the return statement will do. It will either end the closure or it will end the function that contains this code block.
>>
>> This could be disambiguated by using the same syntax as for lazy variables:
>>
>> serverCert.write(to: serverCertificateUrl) { showErrorInKeyWindow(message: message); return }()
>>
>> Now it is clear that the return statement will only terminate the (trailing) closure.
>>
>> A question to the educators on the list: Is this a real problem?
>>
>> Personally, I dislike this situation, but I am also ambivalent towards the solution I just described.
>>
>> Regards,
>> Rien
>>
>> Site: http://balancingrock.nl
>> Blog: http://swiftrien.blogspot.com
>> Github: http://github.com/Balancingrock
>> Project: http://swiftfire.nl
>>
>>
>>
>>
>>
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution@swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution


(Rien) #12

Another solution to the original problem would be to allow the parameter name of the closure outside the functions parenthesis:

func test(a: Int, onError: ()->Void) {…}

could be called like this:

test(5) onError: { myErrorHandler() }

Myself, I would like this. It makes clear what the closure is used for, and it potentially opens up the possibility to use multiple “parameter named closures” after the function call.

It also makes it clear that this is a closure and not a code block belonging to a statement.

I guess this must have been debated already… if so, why was it rejected?

Regards,
Rien

Site: http://balancingrock.nl
Blog: http://swiftrien.blogspot.com
Github: http://github.com/Balancingrock
Project: http://swiftfire.nl

···

On 20 Mar 2017, at 13:13, David Rönnqvist via swift-evolution <swift-evolution@swift.org> wrote:

Xcode can already draw boxes for nesting scopes, but it’s disabled by default. You’ll find it under: Editor > Code Folding > Focus Follows Selection.

That said, IIRC it’s been mentioned on this list that (I’m paraphrasing) we should try and avoid designs that rely on editor functionality, and also that a Xcode is independent from the mailing list.

On 20 Mar 2017, at 07:22, Rick Mann via swift-evolution <swift-evolution@swift.org> wrote:

I actually don't like this situation, either. I find it gets a bit confusing to know what's a block and what's just nested scope. I, too, have had an impulse to have a different keyword for returning from a block, but what I really want is for the entire scope of the block to be called out differently.

This is true regardless of whether or not it's a trailing closure.

I wonder if the source editor (e.g. Xcode) could draw three sides of a box with arrows:

  { <--------------------+
      some code |
      more code |
  } <--------------------+

I don't know if this would quickly get messy and distracting. It would be challenging to find exactly the right way to draw it that pleases everyone (it should, obviously, be hyper-customizable, but Apple hates settings), and to draw it to make it easy to see what it's pointing to without trampling over end-of-line comments.

Maybe subtle highlighting of the background (all the way across the window) to show block, but that makes it harder to show nested blocks.

On Mar 19, 2017, at 20:33 , Kenny Leung via swift-evolution <swift-evolution@swift.org> wrote:

I have proposed that a different keyword be used to return out of blocks. In Objective-C, I have a #define that aliases “blockreturn” and I use that exclusively in breaking out of blocks.

-Kenny

On Mar 15, 2017, at 3:35 AM, Rien via swift-evolution <swift-evolution@swift.org> wrote:

What does the following code fragment do?

serverCert.write(to: certificateUrl) { showErrorInKeyWindow(message); return }

The only possible answer is: I don’t know.

The problem is finding out what the “return” statement will do.

Without knowing if the {...} is a code block or a trailing closure it is impossible to know what the return statement will do. It will either end the closure or it will end the function that contains this code block.

This could be disambiguated by using the same syntax as for lazy variables:

serverCert.write(to: serverCertificateUrl) { showErrorInKeyWindow(message: message); return }()

Now it is clear that the return statement will only terminate the (trailing) closure.

A question to the educators on the list: Is this a real problem?

Personally, I dislike this situation, but I am also ambivalent towards the solution I just described.

Regards,
Rien

Site: http://balancingrock.nl
Blog: http://swiftrien.blogspot.com
Github: http://github.com/Balancingrock
Project: http://swiftfire.nl

_______________________________________________
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

--
Rick Mann
rmann@latencyzero.com

_______________________________________________
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


(Jaden Geller) #13

It seems like your complaint is that control-flow statements, specifically `return`, act different inside closures than inside other braced statements. I too dislike this inconsistency, but I don’t think that the syntactic change you suggested makes it much more clear. I’d rather find a solution that’d allow trailing closure functions (like `forEach`) to support keywords like `return`, though I imagine this would require some sort of macro system.

Cheers,
Jaden Geller

···

On Mar 15, 2017, at 4:56 AM, Rien via swift-evolution <swift-evolution@swift.org> wrote:

Sorry, it seems we are talking past each other, let me try again:

I left the “if” out on purpose. To show that even though the snippet was “valid” code, it was in fact ambiguous.

With closures (and autoclosures) it becomes possible -to some extent- to “enhance” the language.

Consider:

guard let c = somefunc() else { showError(); return }
myguard( let c = somefunc()) { showError(); return }

In this simple example it is clear that the second return behaves quite differently from the first.
It gets more difficult if the code in the block cq closure gets very large.
Also, I would expect that beginners would have problems understanding this (subtile but important) difference.

Regards,
Rien

Site: http://balancingrock.nl
Blog: http://swiftrien.blogspot.com
Github: http://github.com/Balancingrock
Project: http://swiftfire.nl

On 15 Mar 2017, at 12:19, Adrian Zubarev <adrian.zubarev@devandartist.com> wrote:

There is no if … on my screen nor there is one here https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon–20170313/033888.html. May be a typo?

In that case it cannot be a trailing closure because trailing closures are banned in such scenarios. https://github.com/apple/swift-evolution/blob/master/proposals/0056-trailing-closures-in-guard.md

As for the lazy variables you’ve mentioned in the original posts, the closure there is invoked lately but only once and it cannot be reused at all.

Let me know if I understood your gist now.

if someFunction { …; return } // someFunction cannot have a trailing closure here!

--
Adrian Zubarev
Sent with Airmail

Am 15. März 2017 um 12:08:19, Rien (rien@balancingrock.nl) schrieb:

If I wrote this:

if serverCert.write(to: certificateUrl) { showErrorInKeyWindow(message); return }

then the meaning of return would have been different.

Imo it is a problem that two pieces of code impact the understanding of each other and that those two pieces of code could potentially be very far apart.

I do agree that the parenthesis are not a perfect solution, it was just the first thing that I could think of and that has some level of similarity in meaning.

Regards,
Rien

Site: http://balancingrock.nl
Blog: http://swiftrien.blogspot.com
Github: http://github.com/Balancingrock
Project: http://swiftfire.nl

On 15 Mar 2017, at 12:00, Adrian Zubarev <adrian.zubarev@devandartist.com> wrote:

I’m slightly confused by this. How is a trailing closure different from a code block in Swift? It’s basically the same thing with some extra syntax sugar because it happens to be the last parameter of your function.

You can simply write this if you wanted to:

myFucntion(someLabel: abc, closureLabel: { …; return })

Parentheses are indicating that your closure is immediately invoked.

let someInt = { return 42 }()
print(someInt)

let someClosureWhichReturnsAnInt = { return 42 } // You can reuse the closure
print(someClosureWhichReturnsAnInt()) // Invocation happens now here

return is scope based and it’s totally clear (to me) that in your case return will return from your closure with a value of Void.

--
Adrian Zubarev
Sent with Airmail

Am 15. März 2017 um 11:35:39, Rien via swift-evolution (swift-evolution@swift.org) schrieb:

What does the following code fragment do?

serverCert.write(to: certificateUrl) { showErrorInKeyWindow(message); return }

The only possible answer is: I don’t know.

The problem is finding out what the “return” statement will do.

Without knowing if the {...} is a code block or a trailing closure it is impossible to know what the return statement will do. It will either end the closure or it will end the function that contains this code block.

This could be disambiguated by using the same syntax as for lazy variables:

serverCert.write(to: serverCertificateUrl) { showErrorInKeyWindow(message: message); return }()

Now it is clear that the return statement will only terminate the (trailing) closure.

A question to the educators on the list: Is this a real problem?

Personally, I dislike this situation, but I am also ambivalent towards the solution I just described.

Regards,
Rien

Site: http://balancingrock.nl
Blog: http://swiftrien.blogspot.com
Github: http://github.com/Balancingrock
Project: http://swiftfire.nl

_______________________________________________
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


(Adrian Zubarev) #14

I still don’t see your point there. In general you won’t look at parts of parts of a code. Instead you’ll take a chunk that is valid and not ambiguous from the readers perspective. Beginners will bump into that issue, because it’s simply meant to be. Everyone has to lean the difference between break, continue and return in guarded statements and loops. We already have labels to exit specific nested loops. Maybe that is also the way return could go?

Something like:

func foo() -> Int {
     
label:

    [1,2,3,4,5, …].forEach {
     
        // Do something
        // If certain condition is met abort and return from the parent scope
        return(label) 42
    }
     
    return 0
}

···

--
Adrian Zubarev
Sent with Airmail

Am 15. März 2017 um 12:56:31, Rien (rien@balancingrock.nl) schrieb:

Sorry, it seems we are talking past each other, let me try again:

I left the “if” out on purpose. To show that even though the snippet was “valid” code, it was in fact ambiguous.

With closures (and autoclosures) it becomes possible -to some extent- to “enhance” the language.

Consider:

guard let c = somefunc() else { showError(); return }
myguard( let c = somefunc()) { showError(); return }

In this simple example it is clear that the second return behaves quite differently from the first.
It gets more difficult if the code in the block cq closure gets very large.
Also, I would expect that beginners would have problems understanding this (subtile but important) difference.

Regards,
Rien

Site: http://balancingrock.nl
Blog: http://swiftrien.blogspot.com
Github: http://github.com/Balancingrock
Project: http://swiftfire.nl

On 15 Mar 2017, at 12:19, Adrian Zubarev <adrian.zubarev@devandartist.com> wrote:

There is no if … on my screen nor there is one here https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon–20170313/033888.html. May be a typo?

In that case it cannot be a trailing closure because trailing closures are banned in such scenarios. https://github.com/apple/swift-evolution/blob/master/proposals/0056-trailing-closures-in-guard.md

As for the lazy variables you’ve mentioned in the original posts, the closure there is invoked lately but only once and it cannot be reused at all.

Let me know if I understood your gist now.

if someFunction { …; return } // someFunction cannot have a trailing closure here!

--
Adrian Zubarev
Sent with Airmail

Am 15. März 2017 um 12:08:19, Rien (rien@balancingrock.nl) schrieb:

If I wrote this:

if serverCert.write(to: certificateUrl) { showErrorInKeyWindow(message); return }

then the meaning of return would have been different.

Imo it is a problem that two pieces of code impact the understanding of each other and that those two pieces of code could potentially be very far apart.

I do agree that the parenthesis are not a perfect solution, it was just the first thing that I could think of and that has some level of similarity in meaning.

Regards,
Rien

Site: http://balancingrock.nl
Blog: http://swiftrien.blogspot.com
Github: http://github.com/Balancingrock
Project: http://swiftfire.nl

> On 15 Mar 2017, at 12:00, Adrian Zubarev <adrian.zubarev@devandartist.com> wrote:
>
> I’m slightly confused by this. How is a trailing closure different from a code block in Swift? It’s basically the same thing with some extra syntax sugar because it happens to be the last parameter of your function.
>
> You can simply write this if you wanted to:
>
> myFucntion(someLabel: abc, closureLabel: { …; return })
>
> Parentheses are indicating that your closure is immediately invoked.
>
> let someInt = { return 42 }()
> print(someInt)
>
> let someClosureWhichReturnsAnInt = { return 42 } // You can reuse the closure
> print(someClosureWhichReturnsAnInt()) // Invocation happens now here
>
> return is scope based and it’s totally clear (to me) that in your case return will return from your closure with a value of Void.
>
>
>
>
> --
> Adrian Zubarev
> Sent with Airmail
>
> Am 15. März 2017 um 11:35:39, Rien via swift-evolution (swift-evolution@swift.org) schrieb:
>
>> What does the following code fragment do?
>>
>> serverCert.write(to: certificateUrl) { showErrorInKeyWindow(message); return }
>>
>> The only possible answer is: I don’t know.
>>
>> The problem is finding out what the “return” statement will do.
>>
>> Without knowing if the {...} is a code block or a trailing closure it is impossible to know what the return statement will do. It will either end the closure or it will end the function that contains this code block.
>>
>> This could be disambiguated by using the same syntax as for lazy variables:
>>
>> serverCert.write(to: serverCertificateUrl) { showErrorInKeyWindow(message: message); return }()
>>
>> Now it is clear that the return statement will only terminate the (trailing) closure.
>>
>> A question to the educators on the list: Is this a real problem?
>>
>> Personally, I dislike this situation, but I am also ambivalent towards the solution I just described.
>>
>> Regards,
>> Rien
>>
>> Site: http://balancingrock.nl
>> Blog: http://swiftrien.blogspot.com
>> Github: http://github.com/Balancingrock
>> Project: http://swiftfire.nl
>>
>>
>>
>>
>>
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution@swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution


(Rien) #15

It seems like your complaint is that control-flow statements, specifically `return`, act different inside closures than inside other braced statements.

Yes.
break and continue also come to mind.

For example if you have some nested loops and you see a “break” statement, you must inspect the code between the loop start and the “break" to check if the break is inside a closure or not.

I too dislike this inconsistency, but I don’t think that the syntactic change you suggested makes it much more clear.

Agree.

As is probably clear from Adrian’s reaction, I am not sure if this really is a problem.
I don’t like it, but the current situation is workable even though it might be confusing to newbies.

···

On 15 Mar 2017, at 13:04, Jaden Geller <jaden.geller@gmail.com> wrote:

I’d rather find a solution that’d allow trailing closure functions (like `forEach`) to support keywords like `return`, though I imagine this would require some sort of macro system.

Cheers,
Jaden Geller

On Mar 15, 2017, at 4:56 AM, Rien via swift-evolution <swift-evolution@swift.org> wrote:

Sorry, it seems we are talking past each other, let me try again:

I left the “if” out on purpose. To show that even though the snippet was “valid” code, it was in fact ambiguous.

With closures (and autoclosures) it becomes possible -to some extent- to “enhance” the language.

Consider:

guard let c = somefunc() else { showError(); return }
myguard( let c = somefunc()) { showError(); return }

In this simple example it is clear that the second return behaves quite differently from the first.
It gets more difficult if the code in the block cq closure gets very large.
Also, I would expect that beginners would have problems understanding this (subtile but important) difference.

Regards,
Rien

Site: http://balancingrock.nl
Blog: http://swiftrien.blogspot.com
Github: http://github.com/Balancingrock
Project: http://swiftfire.nl

On 15 Mar 2017, at 12:19, Adrian Zubarev <adrian.zubarev@devandartist.com> wrote:

There is no if … on my screen nor there is one here https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon–20170313/033888.html. May be a typo?

In that case it cannot be a trailing closure because trailing closures are banned in such scenarios. https://github.com/apple/swift-evolution/blob/master/proposals/0056-trailing-closures-in-guard.md

As for the lazy variables you’ve mentioned in the original posts, the closure there is invoked lately but only once and it cannot be reused at all.

Let me know if I understood your gist now.

if someFunction { …; return } // someFunction cannot have a trailing closure here!

--
Adrian Zubarev
Sent with Airmail

Am 15. März 2017 um 12:08:19, Rien (rien@balancingrock.nl) schrieb:

If I wrote this:

if serverCert.write(to: certificateUrl) { showErrorInKeyWindow(message); return }

then the meaning of return would have been different.

Imo it is a problem that two pieces of code impact the understanding of each other and that those two pieces of code could potentially be very far apart.

I do agree that the parenthesis are not a perfect solution, it was just the first thing that I could think of and that has some level of similarity in meaning.

Regards,
Rien

Site: http://balancingrock.nl
Blog: http://swiftrien.blogspot.com
Github: http://github.com/Balancingrock
Project: http://swiftfire.nl

On 15 Mar 2017, at 12:00, Adrian Zubarev <adrian.zubarev@devandartist.com> wrote:

I’m slightly confused by this. How is a trailing closure different from a code block in Swift? It’s basically the same thing with some extra syntax sugar because it happens to be the last parameter of your function.

You can simply write this if you wanted to:

myFucntion(someLabel: abc, closureLabel: { …; return })

Parentheses are indicating that your closure is immediately invoked.

let someInt = { return 42 }()
print(someInt)

let someClosureWhichReturnsAnInt = { return 42 } // You can reuse the closure
print(someClosureWhichReturnsAnInt()) // Invocation happens now here

return is scope based and it’s totally clear (to me) that in your case return will return from your closure with a value of Void.

--
Adrian Zubarev
Sent with Airmail

Am 15. März 2017 um 11:35:39, Rien via swift-evolution (swift-evolution@swift.org) schrieb:

What does the following code fragment do?

serverCert.write(to: certificateUrl) { showErrorInKeyWindow(message); return }

The only possible answer is: I don’t know.

The problem is finding out what the “return” statement will do.

Without knowing if the {...} is a code block or a trailing closure it is impossible to know what the return statement will do. It will either end the closure or it will end the function that contains this code block.

This could be disambiguated by using the same syntax as for lazy variables:

serverCert.write(to: serverCertificateUrl) { showErrorInKeyWindow(message: message); return }()

Now it is clear that the return statement will only terminate the (trailing) closure.

A question to the educators on the list: Is this a real problem?

Personally, I dislike this situation, but I am also ambivalent towards the solution I just described.

Regards,
Rien

Site: http://balancingrock.nl
Blog: http://swiftrien.blogspot.com
Github: http://github.com/Balancingrock
Project: http://swiftfire.nl

_______________________________________________
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


(Haravikk) #16

When you get onto that kind of syntax the obvious question is, what's wrong with:

  test(5, onError: { myErrorHandler() })

To me there's no real difference, in fact all that's changed now is that a round bracket is at the end; while being within the parenthesis is a little noisier, it's also clearer what's going on. Consider, if the body of the closure were very long:

  test(5, onError: {
    // Lots
    // and
    // lots
    // of
    // code
  })

Here the closing round bracket reminds me that this is the end of a closure being passed to a function, rather than some other code block and, if properly indented, it should be easy to jump to whatever that function is.

It could just be my personal preference; I'm generally uncomfortable with the use of trailing closures except for language-like constructs such as .forEach, and I've never had any problem using closures within the function's parenthesis, but it just seems like there's a point at which we're bolting so much onto trailing closures, that you really do have to ask what's so wrong with just passing the closure normally?

···

On 20 Mar 2017, at 14:24, Rien via swift-evolution <swift-evolution@swift.org> wrote:

Another solution to the original problem would be to allow the parameter name of the closure outside the functions parenthesis:

func test(a: Int, onError: ()->Void) {…}

could be called like this:

test(5) onError: { myErrorHandler() }


(Rick M) #17

Another solution to the original problem would be to allow the parameter name of the closure outside the functions parenthesis:

func test(a: Int, onError: ()->Void) {…}

could be called like this:

test(5) onError: { myErrorHandler() }

I don't think it improves the situation to do this. All this saves is a trailing closing parenthesis and a comma, and it doesn't seem any better than:

test(5, onError: { myErrorHandler() })

or

test(5,
     onError:
     {
         myErrorHandler()
     })

Myself, I would like this. It makes clear what the closure is used for, and it potentially opens up the possibility to use multiple “parameter named closures” after the function call.

It also makes it clear that this is a closure and not a code block belonging to a statement.

I guess this must have been debated already… if so, why was it rejected?

Regards,
Rien

Site: http://balancingrock.nl
Blog: http://swiftrien.blogspot.com
Github: http://github.com/Balancingrock
Project: http://swiftfire.nl

Xcode can already draw boxes for nesting scopes, but it’s disabled by default. You’ll find it under: Editor > Code Folding > Focus Follows Selection.

I tend to agree features should not rely on editors. However, it seems that editor functionality does influence language and API design a lot. I don't have a specific example, but it's a feeling I've been getting lately.

In any case, that Xcode feature (focus follows selection) is interesting, but not really what I'm after. I don't want to see all scopes, I just want to see blocks called out, and I don't want to have to click to find them.

···

On Mar 20, 2017, at 07:24 , Rien <Rien@balancingrock.nl> wrote:

On 20 Mar 2017, at 13:13, David Rönnqvist via swift-evolution <swift-evolution@swift.org> wrote:

That said, IIRC it’s been mentioned on this list that (I’m paraphrasing) we should try and avoid designs that rely on editor functionality, and also that a Xcode is independent from the mailing list.

On 20 Mar 2017, at 07:22, Rick Mann via swift-evolution <swift-evolution@swift.org> wrote:

I actually don't like this situation, either. I find it gets a bit confusing to know what's a block and what's just nested scope. I, too, have had an impulse to have a different keyword for returning from a block, but what I really want is for the entire scope of the block to be called out differently.

This is true regardless of whether or not it's a trailing closure.

I wonder if the source editor (e.g. Xcode) could draw three sides of a box with arrows:

{ <--------------------+
     some code |
     more code |
} <--------------------+

I don't know if this would quickly get messy and distracting. It would be challenging to find exactly the right way to draw it that pleases everyone (it should, obviously, be hyper-customizable, but Apple hates settings), and to draw it to make it easy to see what it's pointing to without trampling over end-of-line comments.

Maybe subtle highlighting of the background (all the way across the window) to show block, but that makes it harder to show nested blocks.

On Mar 19, 2017, at 20:33 , Kenny Leung via swift-evolution <swift-evolution@swift.org> wrote:

I have proposed that a different keyword be used to return out of blocks. In Objective-C, I have a #define that aliases “blockreturn” and I use that exclusively in breaking out of blocks.

-Kenny

On Mar 15, 2017, at 3:35 AM, Rien via swift-evolution <swift-evolution@swift.org> wrote:

What does the following code fragment do?

serverCert.write(to: certificateUrl) { showErrorInKeyWindow(message); return }

The only possible answer is: I don’t know.

The problem is finding out what the “return” statement will do.

Without knowing if the {...} is a code block or a trailing closure it is impossible to know what the return statement will do. It will either end the closure or it will end the function that contains this code block.

This could be disambiguated by using the same syntax as for lazy variables:

serverCert.write(to: serverCertificateUrl) { showErrorInKeyWindow(message: message); return }()

Now it is clear that the return statement will only terminate the (trailing) closure.

A question to the educators on the list: Is this a real problem?

Personally, I dislike this situation, but I am also ambivalent towards the solution I just described.

Regards,
Rien

Site: http://balancingrock.nl
Blog: http://swiftrien.blogspot.com
Github: http://github.com/Balancingrock
Project: http://swiftfire.nl

_______________________________________________
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

--
Rick Mann
rmann@latencyzero.com

_______________________________________________
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

--
Rick Mann
rmann@latencyzero.com


(Rien) #18

The only (slight) advantage is that using trailing closures you can be sure that you have seen all parameters that are necessary inside the function.

Compare:

test(5, onError: {
   // Lots
   // and
   // lots
   // of
   // code
}, 1)

test(5, 1) onError: {
   // Lots
   // and
   // lots
   // of
   // code
}

But I agree, the difference is probably not worth it.

I will start using the inline notation, and see how that works out.

Rien.

···

On 20 Mar 2017, at 15:42, Haravikk <swift-evolution@haravikk.me> wrote:

On 20 Mar 2017, at 14:24, Rien via swift-evolution <swift-evolution@swift.org> wrote:

Another solution to the original problem would be to allow the parameter name of the closure outside the functions parenthesis:

func test(a: Int, onError: ()->Void) {…}

could be called like this:

test(5) onError: { myErrorHandler() }

When you get onto that kind of syntax the obvious question is, what's wrong with:

  test(5, onError: { myErrorHandler() })

To me there's no real difference, in fact all that's changed now is that a round bracket is at the end; while being within the parenthesis is a little noisier, it's also clearer what's going on. Consider, if the body of the closure were very long:

  test(5, onError: {
    // Lots
    // and
    // lots
    // of
    // code
  })

Here the closing round bracket reminds me that this is the end of a closure being passed to a function, rather than some other code block and, if properly indented, it should be easy to jump to whatever that function is.

It could just be my personal preference; I'm generally uncomfortable with the use of trailing closures except for language-like constructs such as .forEach, and I've never had any problem using closures within the function's parenthesis, but it just seems like there's a point at which we're bolting so much onto trailing closures, that you really do have to ask what's so wrong with just passing the closure normally?


(Jaden Geller) #19

It seems like your complaint is that control-flow statements, specifically `return`, act different inside closures than inside other braced statements.

Yes.
break and continue also come to mind.

For example if you have some nested loops and you see a “break” statement, you must inspect the code between the loop start and the “break" to check if the break is inside a closure or not.

I too dislike this inconsistency, but I don’t think that the syntactic change you suggested makes it much more clear.

Agree.

As is probably clear from Adrian’s reaction, I am not sure if this really is a problem.
I don’t like it, but the current situation is workable even though it might be confusing to newbies.

Yeah, either way, I don’t think this is a particularly pressing issue for Swift to address in the next few versions.

Just for fun though, check out Ruby! It allows for both lambdas and anonymous procedures, that latter of which don’t “capture” control-flow keywords. If you say `return` inside a procedure, it’ll return from the function that that called the procedure, not the procedure (aka, if/for/while behavior in Swift)!

···

On Mar 15, 2017, at 5:17 AM, Rien <Rien@Balancingrock.nl> wrote:

On 15 Mar 2017, at 13:04, Jaden Geller <jaden.geller@gmail.com> wrote:

I’d rather find a solution that’d allow trailing closure functions (like `forEach`) to support keywords like `return`, though I imagine this would require some sort of macro system.

Cheers,
Jaden Geller

On Mar 15, 2017, at 4:56 AM, Rien via swift-evolution <swift-evolution@swift.org> wrote:

Sorry, it seems we are talking past each other, let me try again:

I left the “if” out on purpose. To show that even though the snippet was “valid” code, it was in fact ambiguous.

With closures (and autoclosures) it becomes possible -to some extent- to “enhance” the language.

Consider:

guard let c = somefunc() else { showError(); return }
myguard( let c = somefunc()) { showError(); return }

In this simple example it is clear that the second return behaves quite differently from the first.
It gets more difficult if the code in the block cq closure gets very large.
Also, I would expect that beginners would have problems understanding this (subtile but important) difference.

Regards,
Rien

Site: http://balancingrock.nl
Blog: http://swiftrien.blogspot.com
Github: http://github.com/Balancingrock
Project: http://swiftfire.nl

On 15 Mar 2017, at 12:19, Adrian Zubarev <adrian.zubarev@devandartist.com> wrote:

There is no if … on my screen nor there is one here https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon–20170313/033888.html. May be a typo?

In that case it cannot be a trailing closure because trailing closures are banned in such scenarios. https://github.com/apple/swift-evolution/blob/master/proposals/0056-trailing-closures-in-guard.md

As for the lazy variables you’ve mentioned in the original posts, the closure there is invoked lately but only once and it cannot be reused at all.

Let me know if I understood your gist now.

if someFunction { …; return } // someFunction cannot have a trailing closure here!

--
Adrian Zubarev
Sent with Airmail

Am 15. März 2017 um 12:08:19, Rien (rien@balancingrock.nl) schrieb:

If I wrote this:

if serverCert.write(to: certificateUrl) { showErrorInKeyWindow(message); return }

then the meaning of return would have been different.

Imo it is a problem that two pieces of code impact the understanding of each other and that those two pieces of code could potentially be very far apart.

I do agree that the parenthesis are not a perfect solution, it was just the first thing that I could think of and that has some level of similarity in meaning.

Regards,
Rien

Site: http://balancingrock.nl
Blog: http://swiftrien.blogspot.com
Github: http://github.com/Balancingrock
Project: http://swiftfire.nl

On 15 Mar 2017, at 12:00, Adrian Zubarev <adrian.zubarev@devandartist.com> wrote:

I’m slightly confused by this. How is a trailing closure different from a code block in Swift? It’s basically the same thing with some extra syntax sugar because it happens to be the last parameter of your function.

You can simply write this if you wanted to:

myFucntion(someLabel: abc, closureLabel: { …; return })

Parentheses are indicating that your closure is immediately invoked.

let someInt = { return 42 }()
print(someInt)

let someClosureWhichReturnsAnInt = { return 42 } // You can reuse the closure
print(someClosureWhichReturnsAnInt()) // Invocation happens now here

return is scope based and it’s totally clear (to me) that in your case return will return from your closure with a value of Void.

--
Adrian Zubarev
Sent with Airmail

Am 15. März 2017 um 11:35:39, Rien via swift-evolution (swift-evolution@swift.org) schrieb:

What does the following code fragment do?

serverCert.write(to: certificateUrl) { showErrorInKeyWindow(message); return }

The only possible answer is: I don’t know.

The problem is finding out what the “return” statement will do.

Without knowing if the {...} is a code block or a trailing closure it is impossible to know what the return statement will do. It will either end the closure or it will end the function that contains this code block.

This could be disambiguated by using the same syntax as for lazy variables:

serverCert.write(to: serverCertificateUrl) { showErrorInKeyWindow(message: message); return }()

Now it is clear that the return statement will only terminate the (trailing) closure.

A question to the educators on the list: Is this a real problem?

Personally, I dislike this situation, but I am also ambivalent towards the solution I just described.

Regards,
Rien

Site: http://balancingrock.nl
Blog: http://swiftrien.blogspot.com
Github: http://github.com/Balancingrock
Project: http://swiftfire.nl

_______________________________________________
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


(Rien) #20

I still don’t see your point there. In general you won’t look at parts of parts of a code. Instead you’ll take a chunk that is valid and not ambiguous from the readers perspective.

To me that only works for up to 50 or maybe 70 lines of code. If the modules get larger I tend to miss things that are not directly visible.

Beginners will bump into that issue, because it’s simply meant to be. Everyone has to lean the difference between break, continue and return in guarded statements and loops. We already have labels to exit specific nested loops. Maybe that is also the way return could go?

Maybe, lets wait to see if more people think this is a real problem or not.

Rien.

···

On 15 Mar 2017, at 13:14, Adrian Zubarev <adrian.zubarev@devandartist.com> wrote:

Something like:

func foo() -> Int {
     
label:

    [1,2,3,4,5, …].forEach {
     
        // Do something
        // If certain condition is met abort and return from the parent scope
        return(label) 42
    }
     
    return 0
}

--
Adrian Zubarev
Sent with Airmail

Am 15. März 2017 um 12:56:31, Rien (rien@balancingrock.nl) schrieb:

Sorry, it seems we are talking past each other, let me try again:

I left the “if” out on purpose. To show that even though the snippet was “valid” code, it was in fact ambiguous.

With closures (and autoclosures) it becomes possible -to some extent- to “enhance” the language.

Consider:

guard let c = somefunc() else { showError(); return }
myguard( let c = somefunc()) { showError(); return }

In this simple example it is clear that the second return behaves quite differently from the first.
It gets more difficult if the code in the block cq closure gets very large.
Also, I would expect that beginners would have problems understanding this (subtile but important) difference.

Regards,
Rien

Site: http://balancingrock.nl
Blog: http://swiftrien.blogspot.com
Github: http://github.com/Balancingrock
Project: http://swiftfire.nl

> On 15 Mar 2017, at 12:19, Adrian Zubarev <adrian.zubarev@devandartist.com> wrote:
>
> There is no if … on my screen nor there is one here https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon–20170313/033888.html. May be a typo?
>
> In that case it cannot be a trailing closure because trailing closures are banned in such scenarios. https://github.com/apple/swift-evolution/blob/master/proposals/0056-trailing-closures-in-guard.md
>
> As for the lazy variables you’ve mentioned in the original posts, the closure there is invoked lately but only once and it cannot be reused at all.
>
> Let me know if I understood your gist now.
>
> if someFunction { …; return } // someFunction cannot have a trailing closure here!
>
>
>
>
> --
> Adrian Zubarev
> Sent with Airmail
>
> Am 15. März 2017 um 12:08:19, Rien (rien@balancingrock.nl) schrieb:
>
>> If I wrote this:
>>
>> if serverCert.write(to: certificateUrl) { showErrorInKeyWindow(message); return }
>>
>> then the meaning of return would have been different.
>>
>> Imo it is a problem that two pieces of code impact the understanding of each other and that those two pieces of code could potentially be very far apart.
>>
>> I do agree that the parenthesis are not a perfect solution, it was just the first thing that I could think of and that has some level of similarity in meaning.
>>
>> Regards,
>> Rien
>>
>> Site: http://balancingrock.nl
>> Blog: http://swiftrien.blogspot.com
>> Github: http://github.com/Balancingrock
>> Project: http://swiftfire.nl
>>
>>
>>
>>
>>
>> > On 15 Mar 2017, at 12:00, Adrian Zubarev <adrian.zubarev@devandartist.com> wrote:
>> >
>> > I’m slightly confused by this. How is a trailing closure different from a code block in Swift? It’s basically the same thing with some extra syntax sugar because it happens to be the last parameter of your function.
>> >
>> > You can simply write this if you wanted to:
>> >
>> > myFucntion(someLabel: abc, closureLabel: { …; return })
>> >
>> > Parentheses are indicating that your closure is immediately invoked.
>> >
>> > let someInt = { return 42 }()
>> > print(someInt)
>> >
>> > let someClosureWhichReturnsAnInt = { return 42 } // You can reuse the closure
>> > print(someClosureWhichReturnsAnInt()) // Invocation happens now here
>> >
>> > return is scope based and it’s totally clear (to me) that in your case return will return from your closure with a value of Void.
>> >
>> >
>> >
>> >
>> > --
>> > Adrian Zubarev
>> > Sent with Airmail
>> >
>> > Am 15. März 2017 um 11:35:39, Rien via swift-evolution (swift-evolution@swift.org) schrieb:
>> >
>> >> What does the following code fragment do?
>> >>
>> >> serverCert.write(to: certificateUrl) { showErrorInKeyWindow(message); return }
>> >>
>> >> The only possible answer is: I don’t know.
>> >>
>> >> The problem is finding out what the “return” statement will do.
>> >>
>> >> Without knowing if the {...} is a code block or a trailing closure it is impossible to know what the return statement will do. It will either end the closure or it will end the function that contains this code block.
>> >>
>> >> This could be disambiguated by using the same syntax as for lazy variables:
>> >>
>> >> serverCert.write(to: serverCertificateUrl) { showErrorInKeyWindow(message: message); return }()
>> >>
>> >> Now it is clear that the return statement will only terminate the (trailing) closure.
>> >>
>> >> A question to the educators on the list: Is this a real problem?
>> >>
>> >> Personally, I dislike this situation, but I am also ambivalent towards the solution I just described.
>> >>
>> >> Regards,
>> >> Rien
>> >>
>> >> Site: http://balancingrock.nl
>> >> Blog: http://swiftrien.blogspot.com
>> >> Github: http://github.com/Balancingrock
>> >> Project: http://swiftfire.nl
>> >>
>> >>
>> >>
>> >>
>> >>
>> >> _______________________________________________
>> >> swift-evolution mailing list
>> >> swift-evolution@swift.org
>> >> https://lists.swift.org/mailman/listinfo/swift-evolution
>>