on Mon Jan 16 2017, Charles Srstka <cocoadev-AT-charlessoft.com> wrote:

> On Jan 16, 2017, at 6:42 PM, Dave Abrahams via swift-evolution 
> <[email protected]> wrote:
>> 
>> 
>> on Mon Jan 16 2017, Charles Srstka <[email protected]
>> <mailto:[email protected]>> wrote:
>> 
>
>>>> On Jan 16, 2017, at 7:49 AM, Chris Eidhof via swift-evolution 
>>>> <[email protected]> wrote:
>>>> 
>>>> Hi,
>>>> 
>>>> How does everyone feel about adding a second version of `reduce` to
>>> 
>>>> `Sequence`? Instead of a `combine` function that's of type `(A,
>>>> Element) -> A`, it would be `(inout A, Element) -> ()`. This way, we
>>>> can write nice functionals algorithms, but have the benefits of
>>>> inout (mutation within the function, and hopefully some copy
>>>> eliminations).
>>>> 
>>>> IIRC, Loïc Lecrenier first asked this on Twitter. I've been using it
>>>> ever since, because it can really improve readability (the possible
>>>> performance gain is nice, too).
>>>> 
>>>> Here's `reduce` with an `inout` parameter, including a sample:
>>>> https://gist.github.com/chriseidhof/fd3e9aa621569752d1b04230f92969d7
>>>> 
>>>> -- 
>>>> Chris Eidhof
>>> 
>>> I did this in my own private code a while ago. There is one drawback, which 
>>> is that Swift’s type
>>> inference system isn’t quite up to handling it. For example, doing this 
>>> results in an “ambiguous
>>> reference to member” warning:
>>> 
>>> range.reduce([Int]()) { $0.append($1) }
>> 
>> The diagnostic could be better, but the compiler shouldn't let you do
>> that, because it requires passing an unnamed temporary value ([Int]())
>> as inout.
>
> No it doesn’t. The signature of the method is:
>
> func reduce<A>(_ initial: A, combine: (inout A, Iterator.Element) -> ()) -> A
>
> The unnamed temporary value is “initial” here, which is not passed as inout; 
> the inout parameter is
> the first argument to the “combine” closure. The value represented by the 
> ‘initial’ parameter is
> passed to the closure, true, but only after being stored in a not-unnamed 
> ‘var’ variable, as you can
> see from the source of the proposed method:
>
> func reduce<A>(_ initial: A, combine: (inout A, Iterator.Element) -> ()) -> A 
> {
>     var result = initial
>     for element in self {
>         combine(&result, element)
>     }
>     return result
> }
>
> Therefore, I don’t understand this objection.
>
>>> One would think that the type of this closure should be clear:
>>> 
>>> 1) The closure calls append(), a mutating function, so $0 must be inout.
>>> 
>>> 2) The closure doesn’t return anything, which should rule out the
>>> default implementations of reduce,
>> 
>> The closure *does* return something: (), the empty tuple
>
> But it’s not what it’s supposed to return. Sequence’s implementation
> of reduce, which the compiler thinks matches the above, is declared
> like this:
>
> public func reduce<Result>(_ initialResult: Result, _
> nextPartialResult: (Result, Self.Iterator.Element) throws -> Result)
> rethrows -> Result
>
> The closure is supposed to return Result, which in this case would be
> [Int]. It doesn’t, so I’m not sure why the compiler is thinking this
> is a match.

Okay, sounds like I'm totally wrong! Has to happen at least once in a
lifetime, doesn't it? 😉

So please file bug reports for these issues.


-- 
-Dave
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to