> On Feb 16, 2017, at 18:00, Slava Pestov <spes...@apple.com> wrote:
> 
> 
>>> On Feb 16, 2017, at 5:15 PM, David Sweeris via swift-evolution 
>>> <swift-evolution@swift.org> wrote:
>>> 
>>> 
>>> On Feb 16, 2017, at 3:13 PM, David Hart via swift-evolution 
>>> <swift-evolution@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
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to