[swift-evolution] Reduce with inout

Gwendal Roué gwendal.roue at gmail.com
Tue Jan 24 08:43:25 CST 2017


I think you're all fighting against the language, and especially against `inout`. Because you try to copy and then mutate a value, instead of mutating it right away.

I totally understand why: `inout` requires variable declared `var`, and the compiler won't auto-generate it for us. We try to avoid polluting our code with those extra `var` variables. They make code look messy.

But what if we stop fighting? Isn't the following code the correct version of Chris's vision ?

extension Sequence {
    func reduce<A>(mutating result: inout A, _ combine: (inout A, Iterator.Element) -> ()) {
        for element in self {
            combine(&result, element)
        }
    }
}

extension Sequence where Iterator.Element: Equatable {
    func uniq() -> [Iterator.Element] {
        var result: [Iterator.Element] = [] // meh
        reduce(mutating: &result) { (result: inout [Iterator.Element], element) in
            if result.last != element {
                result.append(element)
            }
        }
        return result
    }
}

let x = [1, 1, 2, 3]
x.uniq() // [1, 2, 3]

Yes, the extra `var` variable in the implementation of `uniq` is awful. But that's a limitation of `inout`. Not a limitation of your imagination when you try to find a good name for your method.

I'd suggest us to think about improving Swift so that it starts generating those extra `var` variables for us. It would then give:

func f(i: inout Int) { ... }
f(1) // OK, even if mutated result is lost
let x: Int = 2
f(x) // OK, even if mutated result is lost

And reduce(mutating:) would get rid of the extra var:

extension Sequence {
    func reduce<A>(mutating result: inout A, _ combine: (inout A, Iterator.Element) -> ()) -> A {
        for element in self {
            combine(&result, element)
        }
        return result
    }
}

extension Sequence where Iterator.Element: Equatable {
    func uniq() -> [Iterator.Element] {
        return reduce(mutating: []) { (result: inout [Iterator.Element], element) in
            if result.last != element {
                result.append(element)
            }
        }
    }
}

Gwendal


> Le 24 janv. 2017 à 15:12, Chris Eidhof via swift-evolution <swift-evolution at swift.org> a écrit :
> 
> But if we want to add "copyOf" we should do that to every method that takes a struct? Also, what if you pass in an object?
> 
> I see the concern, but I don't think adding `copyOf` will increase clarity. That said, I'm open to suggestions.
> 
> On Tue, Jan 24, 2017 at 2:43 PM, Xiaodi Wu <xiaodi.wu at gmail.com <mailto:xiaodi.wu at gmail.com>> wrote:
> 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 at swift.org <mailto:swift-evolution at swift.org>> wrote:
> 
> 
> Sent from my iPad
> 
> On Jan 24, 2017, at 1:54 AM, Chris Eidhof via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at 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.
>> 
>> https://github.com/apple/swift-evolution/pull/587 <https://github.com/apple/swift-evolution/pull/587>
>> 
>> On Mon, Jan 23, 2017 at 8:27 AM, Russ Bishop <xenadu at gmail.com <mailto:xenadu at gmail.com>> wrote:
>> 
>>> On Jan 22, 2017, at 10:56 PM, Chris Eidhof <chris at eidhof.nl <mailto:chris at 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 at gmail.com <mailto:xenadu at 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 at swift.org <mailto:swift-evolution at swift.org>
>> https://lists.swift.org/mailman/listinfo/swift-evolution <https://lists.swift.org/mailman/listinfo/swift-evolution>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org <mailto:swift-evolution at swift.org>
> https://lists.swift.org/mailman/listinfo/swift-evolution <https://lists.swift.org/mailman/listinfo/swift-evolution>
> 
> 
> 
> -- 
> Chris Eidhof
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org <mailto:swift-evolution at swift.org>
> https://lists.swift.org/mailman/listinfo/swift-evolution <https://lists.swift.org/mailman/listinfo/swift-evolution>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170124/3569a947/attachment.html>


More information about the swift-evolution mailing list