<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"></head><body dir="auto"><div><br></div><div>On Feb 16, 2017, at 09:03, T.J. Usiyan via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a>&gt; wrote:<br><br></div><blockquote type="cite"><div><div dir="ltr"><div># Pure Functions</div><div><br></div><div>* Proposal: [SE-NNNN](<a href="https://github.com/apple/swift-evolution/blob/master/proposals/NNNN-name.md">https://github.com/apple/swift-evolution/blob/master/proposals/NNNN-name.md</a>)</div><div>* Author(s): [TJ Usiyan](<a href="https://github.com/griotspeak">https://github.com/griotspeak</a>)</div><div>* Status: **Awaiting review**</div><div>* Review manager: TBD</div><div><br></div><div>## Introduction</div><div><br></div><div>Some functions are, essentially, only meant to be transformations of their input and–as such–do not and should not reference any variables other than those passed in. These same functions are not meant to have any effects other than the aforementioned transformation of input. Currently, Swift cannot assist the developer and confirm that any given function is one of these 'pure' functions. To facilitate this, this proposal adds syntax to signal that a function is 'pure'.</div><div><br></div><div>'pure', in this context, means:</div><div>1. The function must have a return value</div><div>1. This function can only call other pure functions</div><div>1. This function cannot access/modify global or static variables.</div><div><br></div><div>## Motivation</div><div><br></div><div>Consider the following example where `_computeNullability(of:)` is meant to create its output solely based on the provided recognizer.</div><div><br></div><div>```</div><div>class Recognizer {</div><div><span class="gmail-Apple-tab-span" style="white-space:pre">        </span>var nullabilityMemo: Bool?</div><div><span class="gmail-Apple-tab-span" style="white-space:pre">        </span>var isNullable: Bool {</div><div><span class="gmail-Apple-tab-span" style="white-space:pre">                </span>func _computeNullability(of recognizer: Recognizer) -&gt; Bool {…}</div><div><span class="gmail-Apple-tab-span" style="white-space:pre">                </span>if let back = nullabilityMemo {</div><div><span class="gmail-Apple-tab-span" style="white-space:pre">                        </span>return back<span class="gmail-Apple-tab-span" style="white-space:pre">                </span></div><div><span class="gmail-Apple-tab-span" style="white-space:pre">                </span>} else {</div><div><span class="gmail-Apple-tab-span" style="white-space:pre">                        </span>let back = &nbsp;_computeNullability(of: self)</div><div><span class="gmail-Apple-tab-span" style="white-space:pre">                        </span>nullabilityMemo = back</div><div><span class="gmail-Apple-tab-span" style="white-space:pre">                        </span>return back</div><div><span class="gmail-Apple-tab-span" style="white-space:pre">                </span>}</div><div><span class="gmail-Apple-tab-span" style="white-space:pre">        </span>}</div><div>}</div><div>```</div><div>if `_computeNullability(of:)` is recursive at all, there exists a real potential to accidentally reference `self` in its body and the mistake, depending on circumstance, can be terribly subtle. Converting `_computeNullability(of:)` to a `static` function is an option but obfuscates the fact that it is *only* to be called within `isNullable`.</div><div><br></div><div><br></div><div>## Proposed solution</div><div><br></div><div>Given the ability to indicate that `_computeNullability(of:)` is a 'pure' function, the developer gains assurance from the tooling that it doesn't reference anything or cause any side effects.</div><div><br></div><div><br></div><div>```</div><div>class Recognizer {</div><div><span class="gmail-Apple-tab-span" style="white-space:pre">        </span>var nullabilityMemo: Bool?</div><div><span class="gmail-Apple-tab-span" style="white-space:pre">        </span>var isNullable: Bool {</div><div><span class="gmail-Apple-tab-span" style="white-space:pre">                </span>pfunc _computeNullability(of recognizer: Recognizer) -&gt; Bool {…}</div><div><span class="gmail-Apple-tab-span" style="white-space:pre">                </span>if let back = nullabilityMemo {</div><div><span class="gmail-Apple-tab-span" style="white-space:pre">                        </span>return back<span class="gmail-Apple-tab-span" style="white-space:pre">                </span></div><div><span class="gmail-Apple-tab-span" style="white-space:pre">                </span>} else {</div><div><span class="gmail-Apple-tab-span" style="white-space:pre">                        </span>let back = &nbsp;_computeNullability(of: self)</div><div><span class="gmail-Apple-tab-span" style="white-space:pre">                        </span>nullabilityMemo = back</div><div><span class="gmail-Apple-tab-span" style="white-space:pre">                        </span>return back</div><div><span class="gmail-Apple-tab-span" style="white-space:pre">                </span>}</div><div><span class="gmail-Apple-tab-span" style="white-space:pre">        </span>}</div><div>}</div><div>```</div><div><br></div><div>## Detailed design</div><div><br></div><div>This proposal introduces a new annotation `=&gt;`, which is to be accepted everywhere `-&gt;` currently is. Members created using this kewyord must follow the rules listed in the introduction.</div><div><br></div><div>## Impact on existing code</div><div><br></div><div>This is an additive feature unless alternative 2 is chosen and, as such, should not require an effect on existing code. It could be used to annotate closures accepted by methods in the standard library such as `map`, `filter`, and `reduce`. While this would fit well with their typical use, such a change is not necessarily part of this proposal.</div><div><br></div><div>## Alternatives considered</div><div><br></div><div>It should be noted that neither of these alternatives can remain consistent for inline closures.</div><div>1. keyword `pfunc` (pronounciation: pifəŋk) for 'pure' functions.&nbsp;</div><div>2. `proc` keyword for 'impure' functions and 'func' for 'pure' functions. This would be a massively source breaking change and, as such, is unlikely to have any feasibility. It is, however, the most clean semantically, in my opinion.</div></div></div></blockquote><br><div>Could we use pure functions as the basis of "type functions"? That is, functions that operate on, and return, types rather than variables. For example, the "N+P" part of the return type in:</div><div>&nbsp; &nbsp; func append &lt;M,N,P&gt; (lhs: Matrix&lt;M,N&gt;, rhs: Matrix&lt;M,N,P&gt;) -&gt; Matrix&lt;M, N+P&gt; {...}</div><div>(where M,N, and P all conform to "Length" or something, since Int literals can't be generic parameters yet.) Because something like that would come in real handy for matrix and vector types.</div><div><br></div><div>I know this feature would have to be a separate proposal... I was just thinking of potential applications of pure functions, since somebody was asking earlier in the thread.</div><div><br></div><div>- Dave Sweeris</div><div><br></div><div><br></div></body></html>