> On Jan 16, 2017, at 8:10 PM, Dave Abrahams via swift-evolution 
> <swift-evolution@swift.org> wrote:
> 
> 
> 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 
>> <swift-evolution@swift.org> wrote:
>>> 
>>> 
>>> on Mon Jan 16 2017, Charles Srstka <swift-evolution@swift.org
>>> <mailto:swift-evolution@swift.org>> wrote:
>>> 
>> 
>>>>> On Jan 16, 2017, at 7:49 AM, Chris Eidhof via swift-evolution 
>>>>> <swift-evolution@swift.org> 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.

This one should already be fixed in master. If it isn't, definitely file a new 
one!

-Joe
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to