[swift-evolution] [Review] SE-0073: Marking closures as executing exactly once

Pyry Jahkola pyry.jahkola at iki.fi
Wed May 4 04:55:42 CDT 2016


Hi Gwendal,

Nice writeup. So I see that you recognise how this extra specification will complicate (while also facilitate) things. And I also see that you're a co-author of the proposal. So I'm more than happy if you can squeeze this extra into it.

However reading your example code, I had to squint to see—without the compiler's squiggly red aid—what all the problematic cases are.

1) Is it obvious to everybody why you can't always use `x` in the end of Cases 2 and 4? For example, with `if—else` you MUST initialise the variable or escape its scope in all branches; you can't just write the following to complete the initialisation later:

    let x: Int
    if cond { x = 1 }
    // ...
    if !cond { x = 2 } // too late!

2) Should Cases 2 and 4 be made illegal? The requirement could then be that all `catch` blocks either:
2.a) initialise another value for `x`, or
2.b) escape the scope using `throw`, `return`, `fatalError`, whatnot…

3) If you consider including this addition to the proposal, it might also help other reviewers if you explained how the compiler will be able to help the programmer write a valid program. E.g. what would the error messages about partially initialised variables look like? And where and when would they appear? Could the compiler suggest certain fixits? Etc.

So, I'm all +1 and very glad if you can make it! (But also somewhat sceptical whether it could get accepted.)

— Pyry

> On 04 May 2016, at 12:24, Gwendal Roué <gwendal.roue at gmail.com> wrote:
> 
> I quite expect being able to throw out of a @noescape(once) block. Maybe the sentence "it must not be executed on any path that throws" should be removed from the proposal, should it have the implications you describe.
> 
> Here is below what I expect this proposal to allow. So you see one problematic case?
> 
> 	// Function which rethrows closure errors:
> 	func f1(closure: @noescape(once) () throws -> ()) rethrows {
> 		try closure()
> 	}
> 
> 	// Function which may throw before, inside, or after the closure:
> 	func f2(closure: @noescape(once) () throws -> ()) throws {
> 		try mayFailBefore()
> 		try closure()
> 		try mayFailAfter()
> 	}
> 	
> 	// Support function
> 	func getX() throws -> Int { return 1 }
> 	
> Case 1:
> 
> 	let x: Int
> 	f1 {
> 		x = 1
> 		// use x
> 	}
> 	// use x
> 	
> Case 2:
> 
> 	let x: Int
> 	do {
> 		try f1 {
> 			x = try getX()
> 			// use x
> 		}
> 		// use x
> 	} catch {
> 		// can't use x
> 	}
> 	// can't use x
> 	
> Case 3:
> 
> 	let x: Int
> 	do {
> 		try f1 {
> 			x = try getX()
> 			// use x
> 		}
> 		// use x
> 	} catch {
> 		x = 1
> 	}
> 	// use x
> 	
> Case 4:
> 
> 	let x: Int
> 	do {
> 		try f2 {
> 			x = try getX()
> 			// use x
> 		}
> 		// use x
> 	} catch {
> 		// can't use x
> 	}
> 	// can't use x
> 
> Case 5:
> 
> 	let x: Int
> 	do {
> 		try f2 {
> 			x = try getX()
> 			// use x
> 		}
> 		// use x
> 	} catch {
> 		x = 1
> 	}
> 	// use x
> 
> Gwendal Roué
> 


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160504/f7fdacf5/attachment.html>


More information about the swift-evolution mailing list