[swift-evolution] [Pitch] Support for pure functions. Part n + 1.

David Sweeris davesweeris at mac.com
Thu Feb 16 20:20:57 CST 2017


> On Feb 16, 2017, at 18:00, Slava Pestov <spestov at apple.com> wrote:
> 
> 
>>> On Feb 16, 2017, at 5:15 PM, David Sweeris via swift-evolution <swift-evolution at swift.org> wrote:
>>> 
>>> 
>>> On Feb 16, 2017, at 3:13 PM, David Hart via swift-evolution <swift-evolution at swift.org> wrote:
>>> 
>>> Now that I've thought more about it, I have a question. Escaping/unescaping is an important concept to have in the language: if the API provider makes the promise that a closure is non-escaping, the API client doesn't have to worry about the closure capturing variables and creating strong references to them.
>>> 
>>> But in the case of pure functions, I fail to get the benefit from the examples. Could someone explain to me the advantages with a more in-depth example?
>> 
>> AFAIK, the two most direct benefits are memoization (without an “r”) and concurrency. Because the everything the function does is contained within the function itself and it can’t change or be affected by any global state, the compiler can prove it’s ok to, for instance, parallelize a loop for you if everything inside the loop is “pure". Additionally, because a pure function will always give you the same output for the same input, you (or the compiler, if it supports that level of optimization) can safely cache the results of a function call in a Dictionary or something, and next time the function is called do a quick lookup to see if you already know the answer before passing the inputs along to the “real" function. The benefits of this obviously depend on what the function is doing… it wouldn’t make sense to cache simple integer addition, but if your function has, IDK, loops nested 23 levels deep and they all involve floating point division and matrix multiplication or something, caching the answer will likely pay off.
> 
> I think memoization should be opt-in rather than something the compiler automatically infers. It has non-trivial time and space complexity tradeoffs, and I wouldn’t want the compiler making these decisions behind my back, or the behavior of a program changing between optimized and debug builds.

Oh, totally, yeah (same for auto-parallelization, too... maybe I want those cores doing something else).

Giving the compiler some notion of a "pure function" is a pre-requisite for implementing either in the compiler, though, and in the meantime, having the annotation helps the people trying to manually memoize:

struct Memoizer <T: Hashable, U> {
    var cache = [T:U]()
    let transform: (T)->U
    init(_ transform: @pure (T)->U) {
        self.transform = transform
    }
    subscript(_ arg: T) -> U {
        if let ans = cache[arg] {
            return ans
        } else {
            let ans = transform(arg)
            cache[arg] = ans
            return ans
        }
    }
}

Without the compiler enforcing the @pure part, this becomes unsafe.

- Dave Sweeris
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170216/9b571d3a/attachment.html>


More information about the swift-evolution mailing list