[swift-evolution] Guaranteed closure execution

Gwendal Roué gwendal.roue at gmail.com
Fri Jan 29 03:12:58 CST 2016


Glad we’re a few longing for this feature :-)

You are right Jacob, a modifier `@noescape(once)` would be better, as it would help compiler distinguish between assignment and initialization of captured variables.

The utility of such a new feature is maybe tiny, but clear: it extends the opportunities to declare variables before initializing them. The Swift 1 to 2 transition has already extended those opportunities, so we’re just following an existing trend, here.

As for throwing functions, here is a few proposals:

# No errors

	func f(@noescape(once) once: () ()) {
		once()
	}
	let x: Int
	f { x = 1 }
	print(x) // OK
	
	
# Function declared as throws

	func f(@noescape(once) once: () throws -> ()) throws {
		try once()
	}
	let x: Int
	do {
		try f { x = try ... }
		print(x) // OK: function did not throw so x is initialized
	} catch {
		print(x) // BAD: y may not be initialized
	}


# Function declared as rethrows

	func f(@noescape(once) once: () throws -> ()) rethrows {
		try once()
	}
	
	let x: Int
	f { x = 1 }
	print(x) // OK: function did not throw so x is initialized

	let x: Int
	do {
		try f { x = try ... }
		print(x) // OK: function did not throw so x is initialized
	} catch {
		print(x) // BAD: y may not be initialized
	}

When a rethrowing function has several throwing closures, it does not change much. Generally, if the function throws, then the variable may not be initialized. If it does not throw, the variable is surely initialized.

Gwendal
	
> Le 29 janv. 2016 à 09:23, Jacob Bandes-Storch <jtbandes at gmail.com> a écrit :
> 
> I've wanted something like this as well. I think it would be harder than it seems, because "x = 1" might need to perform initialization, or assignment, depending how it's used.
> 
> It could make sense to have something like "@noescape(executed_exactly_once)" but this might be so limited it's not worth it. And I'm not sure how it should interact with throws.
> 
> Jacob
> 
> On Thu, Jan 28, 2016 at 11:38 PM, Gwendal Roué <swift-evolution at swift.org> wrote:
> Hello,
> 
> I’d like to discuss the opportunity to let functions declare that a closure argument is guaranteed to have been executed when the function has returned.
> 
> For example:
> 
> 	func f(@noescape(executed) closure: () -> ()) {
> 	    closure()
> 	}
> 
> The expected advantage is that the compiler would know that a variable set inside the closure is guaranteed to be initialized, and that it can be used after the execution of the function, as below:
> 
> 	let x: Int  // Not initialized
> 	f { x = 1 }
> 	print(x)    // Guaranteed to be initialized
> 
> Today developers have to write pessimistic code like below:
> 
> 	var x: Int = 0 // `var` declaration, with some irrelevant value
> 	f { x = 1 }
> 	print(x)
> 
> As for a real world usage, I’d like to access a database in a safe (queued) way, and fetch values out of it:
> 
> 	let items: [Item]
> 	let users: [User]
> 	dbQueue.inDatabase { db in
> 	    items = Item.all().fetchAll(db)
> 	    users = Item.all().fetchAll(db)
> 	}
> 
> Gwendal Roué
> 
> 
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
> 
> 



More information about the swift-evolution mailing list