> 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