[swift-evolution] Get rid of #endif

Brent Royal-Gordon brent at architechies.com
Tue Mar 8 18:23:46 CST 2016


Swift inherited an odd preprocessor-related inconsistency from C, and I'm wondering if we should change it.

Swift and C both use curly-bracket blocks to delimit if statements and other runtime control flow:

	if foo {
		blah
	}
	else {
		yadda
	}

However, the preprocessor/build configuration equivalent uses keywords in the style of languages like BASIC:

	#if FOO
		blah
	#else
		blah
	#endif

In addition to the inconsistency, I consider this to have several concrete disadvantages:

- It leaves the preferred indentation of a conditional block ambiguous. Some people indent, others don't.
- It gives us no syntax to build on for other things that should be "scoped". For instance, clang's `#pragma clang diagnostic push/pop` is as strange as it is because there's no sensible way to delimit a block structure.

C justifies this because the preprocessor is a separate pass with its own rules, but Swift does not have this limitation.

Therefore, I suggest we switch to this syntax:

	#if FOO {
		blah
	}
	#else {
		blah
	}

That gives us a basis to cleanly extend compiler directives to add new features. For instance, the #suppress directive discussed in the "[Idea] #suppress(warning-identifier)" could be given a syntax like this:

	#suppress self-in-closure {
		blah
	}

If their design ends up being purely compile-time with no runtime impact, we might even consider using this syntax for behaviors:

	#behavior var lazy<Value>: Value {
		private var value: Value?
		
		get {
			if let value = value {
				return value
			}
			let newValue = initialValue
			value = newValue
			return newValue
		}
		set {
			value = newValue
		}
	}

There are two disadvantages I can identify:

- The fact that a particular } is associated with a compiler directive may not be immediately obvious when reading code.

- `#if swift(...)` may not be able to correctly parse the close of the block if unrecognized new language features inside the block appear to unbalance the curly brackets. (For instance, if a new literal syntax is used to quote a closing curly and older Swift compilers don't recognize it.)

If these problems are considered serious enough, an alternative would be to use `#}` to indicate the close of the compiler directive's scope. This is obviously not an ordinary curly bracket and is unlikely to appear in source for any other reason.

-- 
Brent Royal-Gordon
Architechies



More information about the swift-evolution mailing list