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

Gwendal Roué gwendal.roue at gmail.com
Thu May 5 05:21:07 CDT 2016


> Le 4 mai 2016 à 11:55, Pyry Jahkola <pyry.jahkola at iki.fi> a écrit :
> 
> 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:

Hello Pyry,

In case 2 and 4, you can't always use `x` at the end because there are code paths that do not initialize x.

Let's repeat the case 2 and 4, as a reminder:

Case 2:

	// Function which rethrows closure errors:
	func f1(closure: @noescape(once) () throws -> ()) rethrows {
		try closure()
	}
	let x: Int
	do {
		try f1 {			
			x = try getX()
			// use x
		}
		// use x
	} catch {
		// can't use x
	}
	// can't use x

Case 4:

	// Function which may throw before, inside, or after the closure:
	func f2(closure: @noescape(once) () throws -> ()) throws {
		try mayFailBefore()
		try closure()
		try mayFailAfter()
	}
	let x: Int
	do {
		try f2 {
			x = try getX()
			// use x
		}
		// use x
	} catch {
		// can't use x
	}
	// can't use x

To better explain them, let's replace `f1` with `do`, and `f2` with a throwing function followed with do:

Rewritten case 2:

	let x: Int
	do {
		do {
			x = try getX()
			// use x
		}
		// use x
	} catch {
		// can't use x
	}
	// can't use x

Rewritten case 4:

	let x: Int
	do {
		try mayFail()
		do {
			x = try getX()
			// use x
		}
		// use x
	} catch {
		// can't use x
	}
	// can't use x

The examples above are already the behavior of the Swift compiler. I expect @noescape(once) closures to behave the same (the cases 2 and 4 above)

> 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.

For error messages about partially initialized variables, we just use the regular messages that we already have: `Constant 'x' used before being initialized` error.

Gwendal Roué
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160505/c1fe79fd/attachment.html>


More information about the swift-evolution mailing list