[idea] Make functions with @noescape syntax behave like control structures


(Michael Peternell) #1

I have an idea that touches the Swift compiler, Xcode and the debugger. I'm not sure if any language support is needed for this feature, or if it is just a debugging issue, or just an Xcode issue.

THE PROBLEM

What often irritates me with closure literals, is that you cannot easily step into them. For example:

11 => for(i=0; i<10; i++) {
12 print("i = \(i)")
13 }
14
15 print("done")

When the debugger is in line 11 and I press "Step Over", it goes to line 12. Then to line 13, then to line 11, then to line 12, ..., then to line 15. This is fine.

On the other hand:

23 => myLoopFromFunction(0, 10) {i in
24 print("i = \(i)")
25 }
26
27 print("done")

When the debugger is in line 23 and I press "Step Over", the execution will continue up until line 27. If I want to go to line 24, I have to press the "Step Into" button. If Debug-symbols are enabled for the myLoopFromFunction, this might even work somehow nicely. When having this problem, I usually put a breakpoint into line 24 and press the "Step Over" button. This will put me into line 24. When I reach line 25 I press continue, which will bring me either back to line 24 or it will forward me to line 27.

Even though that particular for-loop and the myLoopFromFunction have exactly the same semantics, the debugging experience is so much nicer with the for-loop. This argument extends to all kinds of @noescape closures, IMO. E.g. to a 'withLock' function, to a 'makeTransactionWithDatabase' function, etc. Stepping into the @noescape closure is usually what we want.

THE PROPOSAL

Whenever you "step over" a function that takes a @noescape closure as the last parameter, and that parameter is specified as a closure literal with the syntax shown in line 23 (after the closing parenthesis), the debugger should behave as if the function were a control structure.

This is feasible: E.g. Xcode could add a hidden breakpoint to the beginning of the closure, and tell LLDB to "step over".

I think the feature should be limited to @noescape closures, because I think they are exactly the ones which are used when you want control-structure-like behavior. Or at least I can't think of a realistic counter example. (Except for functions like dispatch_sync(), which *does* take a close which cannot escape, but the block is not declared as @noescape, so it would not benefit from the proposal.)

ALTERNATIVES

Are there any?

What do you think?

-Michael