[swift-evolution] Proposal: allow arbitrary compile-time code execution

Haravikk swift-evolution at haravikk.me
Mon Feb 8 03:39:25 CST 2016

> On 8 Feb 2016, at 04:29, Steve Richey via swift-evolution <swift-evolution at swift.org> wrote:
> Example:
> ```
> func myFunction() -> String {
> return "hello"
> }
> let myValue = #run myFunction()
> ```
> At compile time, `myFunction` is evaluated and the result inlined to the `myValue` definition. At run time, `myValue` is a `String` containing `"hello"`.
> This is useful for tasks that are relatively expensive to run but only need to be done once, such as lookup tables. Running the algorithm to generate those tables can be handled at compile-time, and the results retrieved at no cost at run time. Furthermore, this structure allows code reuse between the run time and build time code, obviating the need to perform similar tasks in, say, a Swift method and a Python script.

Do we actually need the #run attribute in this case? If the compiler can detect that myFunction() has a fixed return value, or is only ever called once etc., then could it not just optimise away the function call entirely?

For example:

	func powersOfTwo() -> [UIntMax] { // Return an array of the first 64 powers of two.
		var steps = (sizeof(UIntMax) * 8)
		var powers[UIntMax] = [];
		repeat {
			steps -= 1
			powers.append(UIntMax(1) << steps)
		} while (steps > 0)
		return powers

	let powersOfTwoList = powersOfTwo()

Since powersOfTwo() is only ever used once, it can be computed into an array constant; the compiler might already do that, I’m not sure. The main difficulty is whether the compiler can detect code that has no predictable return value, e.g- a call that returns the current time, as this would prevent a function from being precomputed into a constant in this way. There may also be cases where a function’s precomputed value could be very large in which case it might be more desirable to compute it only as needed, though if powersOfTwoList were a static value this wouldn’t matter.

In other words, I think we should be clear on where macros will actually offer functionality that the compiler can’t provide for us, as it seems to me that in the examples given so far we could just use regular code and the compiler can factor it out for us, or we could have an attribute that allows us to indicate which code the compiler should try to factor out. But as a general rule I think if the compiler can factor out unnecessary functions itself, then this could be better in the long run for efficiency anyway, and that’s assuming it doesn’t already do this to some degree (hopefully someone can weigh in on that).
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160208/c309d29c/attachment.html>

More information about the swift-evolution mailing list