Reduce with inout

Any arguments against adding it? Otherwise I'll draft up a short proposal
tomorrow.

···

On Tue, Jan 17, 2017 at 7:24 PM, Joe Groff via swift-evolution < swift-evolution@swift.org> wrote:

> 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:
>>>>> reduce-with-inout.swift · GitHub
>>>>>
>>>>> --
>>>>> 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? :wink:
>
> 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

--
Chris Eidhof

While realizing that this name can cause confusion, I'd still prefer
`reduce(mutating:_:)`, because it looks like the only readable option to me.
Whatever name will be picked, I agree that traditional reduce without
mutation should retain its name.

···

2017-01-18 5:17 GMT+03:00 Xiaodi Wu via swift-evolution < swift-evolution@swift.org>:

A serious possibility would be: `reduce(mutableCopyOf: x) { ... }`.

It's verbose, but the nicer-looking `reduce(mutating: x) { ... }` is
incorrect since, as Charles pointed out to Dave, it's not `x` that's
mutated but rather a mutable copy of it, so it doesn't matter if `x` itself
is declared with `let` or `var`.

What about `reducing(x, combine: {...})`

···

On 18 January 2017 at 07:47, Xiaodi Wu via swift-evolution < swift-evolution@swift.org> wrote:

A serious possibility would be: `reduce(mutableCopyOf: x) { ... }`.

It's verbose, but the nicer-looking `reduce(mutating: x) { ... }` is
incorrect since, as Charles pointed out to Dave, it's not `x` that's
mutated but rather a mutable copy of it, so it doesn't matter if `x` itself
is declared with `let` or `var`.

On Tue, Jan 17, 2017 at 7:46 PM, Sean Heber <sean@fifthace.com> wrote:

`reuse`

Then we just need an excuse for a function named ‘recycle’...

l8r
Sean

> On Jan 17, 2017, at 7:36 PM, T.J. Usiyan via swift-evolution < >> swift-evolution@swift.org> wrote:
>
> `reduceInout`
>
> On Tue, Jan 17, 2017 at 6:30 PM, Xiaodi Wu via swift-evolution < >> swift-evolution@swift.org> wrote:
> Agree. The functional style should keep the functional name.
>
> On Tue, Jan 17, 2017 at 16:18 David Sweeris via swift-evolution < >> swift-evolution@swift.org> wrote:
>
> On Jan 17, 2017, at 16:11, Karl Wagner via swift-evolution < >> swift-evolution@swift.org> wrote:
>
>>
>>> On 17 Jan 2017, at 23:09, Karl Wagner <karl.swift@springsup.com> >> wrote:
>>>
>>>
>>>> On 16 Jan 2017, at 14:49, 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:
reduce-with-inout.swift · GitHub
>>>>
>>>> --
>>>> Chris Eidhof
>>>> _______________________________________________
>>>> swift-evolution mailing list
>>>> swift-evolution@swift.org
>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>
>>> +1
>>>
>>> I would even argue for it to be the default.
>>
>> I mean, assuming having two “reduce”s would stress the typechecker, as
Joe suggested it might, I would say “inout” makes sense to be the default
and the other one can find itself a new name.
>
> IIRC, the "reduce" name comes from functional programming... should the
functional style keep the functional name?
>
> - Dave Sweeris
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

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

--
*Pranshu Goyal*
*iOS Developer*
*tlkn*

A serious possibility would be: `reduce(mutableCopyOf: x) { ... }`.

It's verbose, but the nicer-looking `reduce(mutating: x) { ... }` is incorrect since, as Charles pointed out to Dave, it's not `x` that's mutated but rather a mutable copy of it, so it doesn't matter if `x` itself is declared with `let` or `var`.

Why not also have that version?

var foo = 0
let bar: [SomeType] = ...

bar.reduce(mutating: &foo, someFunction)

// foo now contains the reduced bar

···

On 18 Jan 2017, at 02:17, Xiaodi Wu via swift-evolution <swift-evolution@swift.org> wrote:

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

Not as a direct reply to Russ, but just to reiterate: to me, there are two
clear benefits of using the `inout` version of reduce:

1. The performance (currently discussed at length)
2. Readability (because we can use mutating methods on `inout` arguments).

Even if the compiler were to optimize the unnecessary copy of `return arr +
[el]` away, there are still a lot of other mutable methods that you might
want to use within the reduce closure. So I think the proposal is still
very valid even if the compiler optimizations would magically appear
tomorrow.

To push this proposal forward a little bit, I'd like to come up with a good
name. It seems like we shouldn't overload `reduce`, but choose a different
name, so that we don't stress the typechecker. Any other suggestions?

···

On Mon, Jan 23, 2017 at 7:11 AM, Russ Bishop <xenadu@gmail.com> wrote:

On Jan 20, 2017, at 11:27 PM, Charles Srstka <cocoadev@charlessoft.com> > wrote:

On Jan 21, 2017, at 12:37 AM, Russ Bishop <xenadu@gmail.com> wrote:

On Jan 16, 2017, at 9:43 AM, Charles Srstka via swift-evolution < > swift-evolution@swift.org> wrote:

*I don’t even know how long it actually takes to finish this test, because
the last time I did this I eventually got sick of waiting and killed the
process. So, I don’t know quite how many orders of magnitude slower it is,
but it’s a lot.*

That’s all the endorsement I need. +1 from me.

I do wonder if there is any way to get this sort of optimization out of
the compiler. I suppose it would be difficult because the compiler doesn’t
know what the mutable vs immutable pairs are or if such a pair even exists
(array doesn’t have appending()).

The (somewhat naïve) assumption that some optimization of this sort might
be going on is what led me to do the speed test in the first place.
However, when you think about it, it’d be really quite hard to do. A reduce
that builds an array consists of the closure that adds something to an
array, and the reduce function itself. With the code to both of these, it’s
not inconceivable that the compiler could figure out what you’re doing, but
unfortunately the two components live in different modules / compilation
units. The closure doesn’t know that its return value is just going to be
replacing the passed-in value, and the reduce function doesn’t know that
the closure isn’t going to store the original array somewhere, so neither
can really know that it’s safe to modify the array in place.

Charles

I was thinking of an optimization like this:

1. The closure or function doesn’t capture anything (and thus by
definition nothing can escape the closure)
2. ???
3. Therefore input returns true for isUniquelyReferenced and no copying of
the underlying storage is required (Profit!)

The problem is obviously in step 2. We don’t have any way to express the
necessary contract other than inout, which requires a separate definition.
If it worked like throws/rethrows where a non-mutating closure promoted to
an inout closure then we could just change the definition of reduce (though
you’d still have to return the value). The compiler would need to
understand that ownership of the underlying array storage moves from the
input parameter to the constructed array inside the closure (and ultimately
the return value). That’s a bit of a tall order.

That leads me to think about why inout is required (because
isKnownUniquelyReferenced returns false otherwise). Why can’t the compiler
determine that the intermediate array is unique? Take this program:
func doSomething(_ x: MyStruct) -> MyStruct {
    var mutX = x
    let isUnique = isKnownUniquelyReferenced(&mutX.refTypeInstance)
    print("isUnique = \(isUnique)") //prints false
    return mutX
}
doSomething(MyStruct())

The fact that storage is uniquely owned is trivially provable to a human
but not to the compiler. Why?

These are just idle musings. My suspicion is you need ownership
annotations (aka borrow checker) to make this tractable but I don’t have
any proof of that.

Russ

--
Chris Eidhof

I think it's the right thing for Swift. My main concern would be naming. If they're both named `reduce`, I suspect that will stress the type checker trying to pick an overload based on the context of the closure expression. We're stuck with `reduce` having the value-in-return-out formulation for Swift 3 compatibility; if that weren't the case, I'd argue we only need the `inout` form.

-Joe

···

On Jan 17, 2017, at 11:52 AM, Chris Eidhof <chris@eidhof.nl> wrote:

Any arguments against adding it? Otherwise I'll draft up a short proposal tomorrow.

I suppose as a second-choice I’d go for accumulate(into: with:):

[1, 2, 3].accumulate(into: 0, with: +=)

even [1, 2, 3].accumulate(into: 0, with: -=) doesn’t look so bad IMO.

- Karl

···

On 18 Jan 2017, at 09:00, Anton Zhilin via swift-evolution <swift-evolution@swift.org> wrote:

While realizing that this name can cause confusion, I'd still prefer `reduce(mutating:_:)`, because it looks like the only readable option to me.
Whatever name will be picked, I agree that traditional reduce without mutation should retain its name.

2017-01-18 5:17 GMT+03:00 Xiaodi Wu via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>>:
A serious possibility would be: `reduce(mutableCopyOf: x) { ... }`.

It's verbose, but the nicer-looking `reduce(mutating: x) { ... }` is incorrect since, as Charles pointed out to Dave, it's not `x` that's mutated but rather a mutable copy of it, so it doesn't matter if `x` itself is declared with `let` or `var`.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

I don't think we should replace the current `reduce` with the `inout`
version, also because the current reduce can be really useful as well (e.g.
when the return type is an Int).

One downside of having a different name is that it'll be harder to discover
this version. If stressing the type-checker is the only problem, then maybe
we should improve the type-checker, instead of placing that burden on every
user of the language.

···

On Wed, Jan 18, 2017 at 9:36 AM, Karl Wagner via swift-evolution < swift-evolution@swift.org> wrote:

On 18 Jan 2017, at 09:00, Anton Zhilin via swift-evolution < > swift-evolution@swift.org> wrote:

While realizing that this name can cause confusion, I'd still prefer
`reduce(mutating:_:)`, because it looks like the only readable option to me.
Whatever name will be picked, I agree that traditional reduce without
mutation should retain its name.

2017-01-18 5:17 GMT+03:00 Xiaodi Wu via swift-evolution <
swift-evolution@swift.org>:

A serious possibility would be: `reduce(mutableCopyOf: x) { ... }`.

It's verbose, but the nicer-looking `reduce(mutating: x) { ... }` is
incorrect since, as Charles pointed out to Dave, it's not `x` that's
mutated but rather a mutable copy of it, so it doesn't matter if `x` itself
is declared with `let` or `var`.

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

I suppose as a second-choice I’d go for accumulate(into: with:):

[1, 2, 3].accumulate(into: 0, with: +=)

even [1, 2, 3].accumulate(into: 0, with: -=) doesn’t look so bad IMO.

- Karl

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

--
Chris Eidhof

Sorry for the derail!

reduce(mutating:_:) { } is still my favorite; You can take mutating to mean we will copy the value now but mutate it later.

Some alternatives:

reduce(forMutating:_:) { }

reduce(forInout:_:) { }

reduce(initial:_:) { }

reduce(copying:mutate:) { }

// just kidding...
reduce(copyForLaterMutating:_:) { }

It should definitely be some form of reduce.

Russ

···

On Jan 22, 2017, at 10:56 PM, Chris Eidhof <chris@eidhof.nl> wrote:

Not as a direct reply to Russ, but just to reiterate: to me, there are two clear benefits of using the `inout` version of reduce:

1. The performance (currently discussed at length)
2. Readability (because we can use mutating methods on `inout` arguments).

Even if the compiler were to optimize the unnecessary copy of `return arr + [el]` away, there are still a lot of other mutable methods that you might want to use within the reduce closure. So I think the proposal is still very valid even if the compiler optimizations would magically appear tomorrow.

To push this proposal forward a little bit, I'd like to come up with a good name. It seems like we shouldn't overload `reduce`, but choose a different name, so that we don't stress the typechecker. Any other suggestions?

On Mon, Jan 23, 2017 at 7:11 AM, Russ Bishop <xenadu@gmail.com <mailto:xenadu@gmail.com>> wrote:
--
Chris Eidhof

While we are at it, could we add a inout/mutating version of forEach (unless something like that exists and I missed it)? I have been trying to figure out how to run through an array and call a mutating method on each element without copying everything, and I am at a loss…

Thanks,
Jon

···

On Jan 22, 2017, at 11:27 PM, Russ Bishop via swift-evolution <swift-evolution@swift.org> wrote:

On Jan 22, 2017, at 10:56 PM, Chris Eidhof <chris@eidhof.nl <mailto:chris@eidhof.nl>> wrote:

Not as a direct reply to Russ, but just to reiterate: to me, there are two clear benefits of using the `inout` version of reduce:

1. The performance (currently discussed at length)
2. Readability (because we can use mutating methods on `inout` arguments).

Even if the compiler were to optimize the unnecessary copy of `return arr + [el]` away, there are still a lot of other mutable methods that you might want to use within the reduce closure. So I think the proposal is still very valid even if the compiler optimizations would magically appear tomorrow.

To push this proposal forward a little bit, I'd like to come up with a good name. It seems like we shouldn't overload `reduce`, but choose a different name, so that we don't stress the typechecker. Any other suggestions?

On Mon, Jan 23, 2017 at 7:11 AM, Russ Bishop <xenadu@gmail.com <mailto:xenadu@gmail.com>> wrote:
--
Chris Eidhof

Sorry for the derail!

reduce(mutating:_:) { } is still my favorite; You can take mutating to mean we will copy the value now but mutate it later.

Some alternatives:

reduce(forMutating:_:) { }

reduce(forInout:_:) { }

reduce(initial:_:) { }

reduce(copying:mutate:) { }

// just kidding...
reduce(copyForLaterMutating:_:) { }

It should definitely be some form of reduce.

Russ
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

To me, that sounds more like a monomorphic map? (i.e. a `map` that doesn't
change the type).

···

On Mon, Jan 23, 2017 at 10:07 AM, Jonathan Hull <jhull@gbis.com> wrote:

While we are at it, could we add a inout/mutating version of forEach
(unless something like that exists and I missed it)? I have been trying to
figure out how to run through an array and call a mutating method on each
element without copying everything, and I am at a loss…

Thanks,
Jon

On Jan 22, 2017, at 11:27 PM, Russ Bishop via swift-evolution < > swift-evolution@swift.org> wrote:

On Jan 22, 2017, at 10:56 PM, Chris Eidhof <chris@eidhof.nl> wrote:

Not as a direct reply to Russ, but just to reiterate: to me, there are two
clear benefits of using the `inout` version of reduce:

1. The performance (currently discussed at length)
2. Readability (because we can use mutating methods on `inout` arguments).

Even if the compiler were to optimize the unnecessary copy of `return arr
+ [el]` away, there are still a lot of other mutable methods that you might
want to use within the reduce closure. So I think the proposal is still
very valid even if the compiler optimizations would magically appear
tomorrow.

To push this proposal forward a little bit, I'd like to come up with a
good name. It seems like we shouldn't overload `reduce`, but choose a
different name, so that we don't stress the typechecker. Any other
suggestions?

On Mon, Jan 23, 2017 at 7:11 AM, Russ Bishop <xenadu@gmail.com> wrote:
--
Chris Eidhof

Sorry for the derail!

reduce(mutating:_:) { } is still my favorite; You can take mutating to
mean we will copy the value now but mutate it later.

Some alternatives:

reduce(forMutating:_:) { }

reduce(forInout:_:) { }

reduce(initial:_:) { }

reduce(copying:mutate:) { }

// just kidding...
reduce(copyForLaterMutating:_:) { }

It should definitely be some form of reduce.

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

--
Chris Eidhof

I've thought about it for a few days, and really like `reduce(mutating:_)`.
I've updated the PR, and am now happy for this to go into review.

···

On Mon, Jan 23, 2017 at 8:27 AM, Russ Bishop <xenadu@gmail.com> wrote:

On Jan 22, 2017, at 10:56 PM, Chris Eidhof <chris@eidhof.nl> wrote:

Not as a direct reply to Russ, but just to reiterate: to me, there are two
clear benefits of using the `inout` version of reduce:

1. The performance (currently discussed at length)
2. Readability (because we can use mutating methods on `inout` arguments).

Even if the compiler were to optimize the unnecessary copy of `return arr
+ [el]` away, there are still a lot of other mutable methods that you might
want to use within the reduce closure. So I think the proposal is still
very valid even if the compiler optimizations would magically appear
tomorrow.

To push this proposal forward a little bit, I'd like to come up with a
good name. It seems like we shouldn't overload `reduce`, but choose a
different name, so that we don't stress the typechecker. Any other
suggestions?

On Mon, Jan 23, 2017 at 7:11 AM, Russ Bishop <xenadu@gmail.com> wrote:
--
Chris Eidhof

Sorry for the derail!

reduce(mutating:_:) { } is still my favorite; You can take mutating to
mean we will copy the value now but mutate it later.

Some alternatives:

reduce(forMutating:_:) { }

reduce(forInout:_:) { }

reduce(initial:_:) { }

reduce(copying:mutate:) { }

// just kidding...
reduce(copyForLaterMutating:_:) { }

It should definitely be some form of reduce.

Russ

--
Chris Eidhof

That's a nice sentiment, and there's certainly a lot of work we have yet to do on the type checker to make it generally better. Higher-order functions like `reduce` naturally chain into larger expressions, though, and having such a fundamental sequence operation drag down the type-checker every time you use it would be unfortunate if we can avoid overloading the name.

-Joe

···

On Jan 18, 2017, at 2:11 AM, Chris Eidhof via swift-evolution <swift-evolution@swift.org> wrote:

I don't think we should replace the current `reduce` with the `inout` version, also because the current reduce can be really useful as well (e.g. when the return type is an Int).

One downside of having a different name is that it'll be harder to discover this version. If stressing the type-checker is the only problem, then maybe we should improve the type-checker, instead of placing that burden on every user of the language.

Empathy for the compiler is nice, too, but users and developers are more important. Given that, it seems to me that the default option should be to overload the function, unless the alternative is actually clearer.

In the spirit of comparing burdens, how much more compilation time would be spent if `reduce` is overloaded? How much execution time would be saved by users thanks to developers having found the right option?

This being said, it seems to me that the example that started this discussion (building a collection) is among the worst-performing cases for the functional-style `reduce`. What are other cases where the inout version is a big win? If this is specifically about building collections or sequences, could a more specific type signature help?

Arguing both for and against,
Guillaume Lessard

···

On 18 janv. 2017, at 10:21, Joe Groff via swift-evolution <swift-evolution@swift.org> wrote:

On Jan 18, 2017, at 2:11 AM, Chris Eidhof via swift-evolution <swift-evolution@swift.org> wrote:

If stressing the type-checker is the only problem, then maybe we should improve the type-checker, instead of placing that burden on every user of the language.

That's a nice sentiment, and there's certainly a lot of work we have yet to do on the type checker to make it generally better. Higher-order functions like `reduce` naturally chain into larger expressions, though, and having such a fundamental sequence operation drag down the type-checker every time you use it would be unfortunate if we can avoid overloading the name.

I opened up a WIP PR on the SE repository (so many TLA's!).

I think I'll wait a few days before removing `WIP` until the naming
discussion either reaches consensus or settles down.

So far, I would summarize the thread as: people are in favor, but there is
disagreement on the naming. I suspect the core team will ultimately decide
on the naming?

···

On Wed, Jan 18, 2017 at 11:11 AM, Chris Eidhof <chris@eidhof.nl> wrote:

I don't think we should replace the current `reduce` with the `inout`
version, also because the current reduce can be really useful as well (e.g.
when the return type is an Int).

One downside of having a different name is that it'll be harder to
discover this version. If stressing the type-checker is the only problem,
then maybe we should improve the type-checker, instead of placing that
burden on every user of the language.

On Wed, Jan 18, 2017 at 9:36 AM, Karl Wagner via swift-evolution < > swift-evolution@swift.org> wrote:

On 18 Jan 2017, at 09:00, Anton Zhilin via swift-evolution < >> swift-evolution@swift.org> wrote:

While realizing that this name can cause confusion, I'd still prefer
`reduce(mutating:_:)`, because it looks like the only readable option to me.
Whatever name will be picked, I agree that traditional reduce without
mutation should retain its name.

2017-01-18 5:17 GMT+03:00 Xiaodi Wu via swift-evolution <
swift-evolution@swift.org>:

A serious possibility would be: `reduce(mutableCopyOf: x) { ... }`.

It's verbose, but the nicer-looking `reduce(mutating: x) { ... }` is
incorrect since, as Charles pointed out to Dave, it's not `x` that's
mutated but rather a mutable copy of it, so it doesn't matter if `x` itself
is declared with `let` or `var`.

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

I suppose as a second-choice I’d go for accumulate(into: with:):

[1, 2, 3].accumulate(into: 0, with: +=)

even [1, 2, 3].accumulate(into: 0, with: -=) doesn’t look so bad IMO.

- Karl

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

--
Chris Eidhof

--
Chris Eidhof

>
>>
>> If stressing the type-checker is the only problem, then maybe we should
improve the type-checker, instead of placing that burden on every user of
the language.
>
> That's a nice sentiment, and there's certainly a lot of work we have yet
to do on the type checker to make it generally better. Higher-order
functions like `reduce` naturally chain into larger expressions, though,
and having such a fundamental sequence operation drag down the type-checker
every time you use it would be unfortunate if we can avoid overloading the
name.

Empathy for the compiler is nice, too, but users and developers are more
important. Given that, it seems to me that the default option should be to
overload the function, unless the alternative is actually clearer.

Empathy for users and developers is important, but if the solution adds too
much burden to the type checker and blows up your compile time or gives you
"expression too complex to be solved" errors, then users/developers don't
benefit at all from that either. I don't think it would have been brought
up if there weren't significant concerns about how such an overload would
affect build time or ability to complete. (One of my code bases really
pushes the type checker to its limits and I can sympathize with the
concern.)

···

On Wed, Jan 18, 2017 at 10:33 AM Guillaume Lessard via swift-evolution < swift-evolution@swift.org> wrote:

> On 18 janv. 2017, at 10:21, Joe Groff via swift-evolution < > swift-evolution@swift.org> wrote:
>> On Jan 18, 2017, at 2:11 AM, Chris Eidhof via swift-evolution < > swift-evolution@swift.org> wrote:

In the spirit of comparing burdens, how much more compilation time would
be spent if `reduce` is overloaded? How much execution time would be saved
by users thanks to developers having found the right option?

This being said, it seems to me that the example that started this
discussion (building a collection) is among the worst-performing cases for
the functional-style `reduce`. What are other cases where the inout version
is a big win? If this is specifically about building collections or
sequences, could a more specific type signature help?

Arguing both for and against,
Guillaume Lessard

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

I've thought about it for a few days, and really like `reduce(mutating:_)`.

I'm not a fan of this. It reads in a way that makes it seem like the parameter should be inout, but it isn't. A variation of reduce where the initial value parameter *is* inout is perfectly sensible (whether or not we want it in the standard library). With that in mind, I don't think we should use this name.

Unfortunately I don't have a better suggestion. I think it was Brent who suggested "mutatingCopyOf" which is more accurate, but also undesirably verbose.

···

Sent from my iPad

On Jan 24, 2017, at 1:54 AM, Chris Eidhof via swift-evolution <swift-evolution@swift.org> wrote:

I've updated the PR, and am now happy for this to go into review.

Reduce with inout by chriseidhof · Pull Request #587 · apple/swift-evolution · GitHub

On Mon, Jan 23, 2017 at 8:27 AM, Russ Bishop <xenadu@gmail.com> wrote:

On Jan 22, 2017, at 10:56 PM, Chris Eidhof <chris@eidhof.nl> wrote:

Not as a direct reply to Russ, but just to reiterate: to me, there are two clear benefits of using the `inout` version of reduce:

1. The performance (currently discussed at length)
2. Readability (because we can use mutating methods on `inout` arguments).

Even if the compiler were to optimize the unnecessary copy of `return arr + [el]` away, there are still a lot of other mutable methods that you might want to use within the reduce closure. So I think the proposal is still very valid even if the compiler optimizations would magically appear tomorrow.

To push this proposal forward a little bit, I'd like to come up with a good name. It seems like we shouldn't overload `reduce`, but choose a different name, so that we don't stress the typechecker. Any other suggestions?

On Mon, Jan 23, 2017 at 7:11 AM, Russ Bishop <xenadu@gmail.com> wrote:
--
Chris Eidhof

Sorry for the derail!

reduce(mutating:_:) { } is still my favorite; You can take mutating to mean we will copy the value now but mutate it later.

Some alternatives:

reduce(forMutating:_:) { }

reduce(forInout:_:) { }

reduce(initial:_:) { }

reduce(copying:mutate:) { }

// just kidding...
reduce(copyForLaterMutating:_:) { }

It should definitely be some form of reduce.

Russ

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

Hi,

Looks like there is a typo in the proposal:

    func reduce<A>(mutating: A, _ combine: (inout A, Iterator.Element) -> ()) -> A {
        var result = initial

This makes use of `initial` that is not defined, should be:

    func reduce<A>(mutating initial: A, _ combine: (inout A, Iterator.Element) -> ()) -> A {
        var result = initial

···

Le 24 janv. 2017 à 08:54, Chris Eidhof via swift-evolution <swift-evolution@swift.org> a écrit :

I've thought about it for a few days, and really like `reduce(mutating:_)`. I've updated the PR, and am now happy for this to go into review.

Reduce with inout by chriseidhof · Pull Request #587 · apple/swift-evolution · GitHub

On Mon, Jan 23, 2017 at 8:27 AM, Russ Bishop <xenadu@gmail.com> wrote:

On Jan 22, 2017, at 10:56 PM, Chris Eidhof <chris@eidhof.nl> wrote:

Not as a direct reply to Russ, but just to reiterate: to me, there are two clear benefits of using the `inout` version of reduce:

1. The performance (currently discussed at length)
2. Readability (because we can use mutating methods on `inout` arguments).

Even if the compiler were to optimize the unnecessary copy of `return arr + [el]` away, there are still a lot of other mutable methods that you might want to use within the reduce closure. So I think the proposal is still very valid even if the compiler optimizations would magically appear tomorrow.

To push this proposal forward a little bit, I'd like to come up with a good name. It seems like we shouldn't overload `reduce`, but choose a different name, so that we don't stress the typechecker. Any other suggestions?

On Mon, Jan 23, 2017 at 7:11 AM, Russ Bishop <xenadu@gmail.com> wrote:
--
Chris Eidhof

Sorry for the derail!

reduce(mutating:_:) { } is still my favorite; You can take mutating to mean we will copy the value now but mutate it later.

Some alternatives:

reduce(forMutating:_:) { }

reduce(forInout:_:) { }

reduce(initial:_:) { }

reduce(copying:mutate:) { }

// just kidding...
reduce(copyForLaterMutating:_:) { }

It should definitely be some form of reduce.

Russ

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

It's only verbose if the words aren't needed! The shortest way to describe
something with sufficient accuracy can never be verbose, let alone
undesirable, and I highly agree with this concern. We already have names of
this form, such as `FloatingPoint.init(signOf:magnitudeOf:)`.

···

On Tue, Jan 24, 2017 at 07:33 Matthew Johnson via swift-evolution < swift-evolution@swift.org> wrote:

Sent from my iPad

On Jan 24, 2017, at 1:54 AM, Chris Eidhof via swift-evolution < > swift-evolution@swift.org> wrote:

I've thought about it for a few days, and really like
`reduce(mutating:_)`.

I'm not a fan of this. It reads in a way that makes it seem like the
parameter should be inout, but it isn't. A variation of reduce where the
initial value parameter *is* inout is perfectly sensible (whether or not we
want it in the standard library). With that in mind, I don't think we
should use this name.

Unfortunately I don't have a better suggestion. I think it was Brent who
suggested "mutatingCopyOf" which is more accurate, but also undesirably
verbose.

I've updated the PR, and am now happy for this to go into review.

Reduce with inout by chriseidhof · Pull Request #587 · apple/swift-evolution · GitHub

On Mon, Jan 23, 2017 at 8:27 AM, Russ Bishop <xenadu@gmail.com> wrote:

On Jan 22, 2017, at 10:56 PM, Chris Eidhof <chris@eidhof.nl> wrote:

Not as a direct reply to Russ, but just to reiterate: to me, there are two
clear benefits of using the `inout` version of reduce:

1. The performance (currently discussed at length)
2. Readability (because we can use mutating methods on `inout` arguments).

Even if the compiler were to optimize the unnecessary copy of `return arr
+ [el]` away, there are still a lot of other mutable methods that you might
want to use within the reduce closure. So I think the proposal is still
very valid even if the compiler optimizations would magically appear
tomorrow.

To push this proposal forward a little bit, I'd like to come up with a
good name. It seems like we shouldn't overload `reduce`, but choose a
different name, so that we don't stress the typechecker. Any other
suggestions?

On Mon, Jan 23, 2017 at 7:11 AM, Russ Bishop <xenadu@gmail.com> wrote:
--
Chris Eidhof

Sorry for the derail!

reduce(mutating:_:) { } is still my favorite; You can take mutating to
mean we will copy the value now but mutate it later.

Some alternatives:

reduce(forMutating:_:) { }

reduce(forInout:_:) { }

reduce(initial:_:) { }

reduce(copying:mutate:) { }

// just kidding...
reduce(copyForLaterMutating:_:) { }

It should definitely be some form of reduce.

Russ

--
Chris Eidhof

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

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

Thought: if the idea is performance and not drop-in replacement, why force
the user to incur two copies? If the initial value were inout, this
function would be more unambiguous even without a new name, and at _worst_
the user has to declare a variable with var, a worthwhile trade-off to save
two copies.

(Ack, Jeremy just beat me to it!)

···

On Wed, Jan 18, 2017 at 05:45 Chris Eidhof via swift-evolution < swift-evolution@swift.org> wrote:

I opened up a WIP PR on the SE repository (so many TLA's!).
Reduce with inout by chriseidhof · Pull Request #587 · apple/swift-evolution · GitHub

I think I'll wait a few days before removing `WIP` until the naming
discussion either reaches consensus or settles down.

So far, I would summarize the thread as: people are in favor, but there is
disagreement on the naming. I suspect the core team will ultimately decide
on the naming?

On Wed, Jan 18, 2017 at 11:11 AM, Chris Eidhof <chris@eidhof.nl> wrote:

I don't think we should replace the current `reduce` with the `inout`
version, also because the current reduce can be really useful as well (e.g.
when the return type is an Int).

One downside of having a different name is that it'll be harder to
discover this version. If stressing the type-checker is the only problem,
then maybe we should improve the type-checker, instead of placing that
burden on every user of the language.

On Wed, Jan 18, 2017 at 9:36 AM, Karl Wagner via swift-evolution < > swift-evolution@swift.org> wrote:

On 18 Jan 2017, at 09:00, Anton Zhilin via swift-evolution < > swift-evolution@swift.org> wrote:

While realizing that this name can cause confusion, I'd still prefer
`reduce(mutating:_:)`, because it looks like the only readable option to me.
Whatever name will be picked, I agree that traditional reduce without
mutation should retain its name.

2017-01-18 5:17 GMT+03:00 Xiaodi Wu via swift-evolution <
swift-evolution@swift.org>:

A serious possibility would be: `reduce(mutableCopyOf: x) { ... }`.

It's verbose, but the nicer-looking `reduce(mutating: x) { ... }` is
incorrect since, as Charles pointed out to Dave, it's not `x` that's
mutated but rather a mutable copy of it, so it doesn't matter if `x` itself
is declared with `let` or `var`.

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

I suppose as a second-choice I’d go for accumulate(into: with:):

[1, 2, 3].accumulate(into: 0, with: +=)

even [1, 2, 3].accumulate(into: 0, with: -=) doesn’t look so bad IMO.

- Karl

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

--
Chris Eidhof

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