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

Gwendal Roué gwendal.roue at gmail.com
Wed May 4 04:24:17 CDT 2016


> Le 4 mai 2016 à 08:28, Pyry Jahkola via swift-evolution <swift-evolution at swift.org> a écrit :
> 
> Here's my review of "SE-0073: Marking closures as executing exactly once".
> 
>> What is your evaluation of the proposal?
> 
> +1. I think this is a good idea and should be accepted (without extending the proposed scope).
> 
> However, I think the proposal should be more explicit about the case when (and whether) the block itself throws. Specifically, I think we should highlight that the criterion that
> 
>> it must not be executed on any path that throws
> 
> implies that a @noescape(once) parameter itself cannot throw (until another language change allows otherwise).
> 
> […]
> 
> Being able to throw out of a @noescape(once) block […] would complicate the language by requiring that no one catches the error in the scope where uninitialised variables are defined. I suggest adding this remark to the Future directions.

Hello Pyry,

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é



More information about the swift-evolution mailing list