[swift-evolution] SE-0171: Reduce with inout

Matthew Johnson matthew at anandabits.com
Mon Apr 17 17:10:48 CDT 2017


> On Apr 17, 2017, at 4:59 PM, Jaden Geller <jaden.geller at gmail.com> wrote:
> 
>> 
>> On Apr 17, 2017, at 2:37 PM, Matthew Johnson via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>> 
>> 
>>> On Apr 16, 2017, at 12:47 AM, Dave Abrahams via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>>> 
>>> 
>>> on Fri Apr 14 2017, Matthew Johnson <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>>> 
>>>>> On Apr 14, 2017, at 9:05 PM, David Sweeris <davesweeris at mac.com <mailto:davesweeris at mac.com>> wrote:
>>>>> 
>>>>> 
>>>>>> On Apr 14, 2017, at 15:33, Matthew Johnson via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>>>>>> 
>>>>>> 
>>>>>>>  • What is your evaluation of the proposal?
>>>>>> 
>>>>>> +0.5 because this is a half solution.  I would also like to see a
>>>>>> variant which accepts an inout argument for the reduction to
>>>>>> accumulate into.
>>>>> 
>>>>> Out of curiosity, do you have any particular use case in mind, or do
>>>>> you just think that'd nicely "round out" the reduce functions (which
>>>>> would be fine with me).
>>>> 
>>>> This would be useful in any use case that involves reducing data that
>>>> isn’t all available at the same time for one reason or another
>>>> (batches arrive periodically, data is processed in chunks to avoid
>>>> loading everything into memory, etc).
>>>> 
>>>> IMO the most fundamental variation of `reduce` Swift could offer is
>>>> the one that takes and `inout` accumulator.  The others can easily be
>>>> defined in terms of that.
>>> 
>>> It should work to do this:
>>> 
>>>  existingAccumulator = reduce(into: existingAccumulator) { ... }
>>> 
>>> If reduce is inlined, ARC is doing its job right, and the closure isn't
>>> throwing, it shouldn't even cost a copy of existingAccumulator.
>>> 
>>> If you have a heaviweight accumulator with value semantics and ARC
>>> isn't cutting it for you, you can do this ugly thing instead.
>>> 
>>>  extension Optional {
>>>    mutating func release() -> Wrapped {
>>>      defer { self = nil }
>>>      return self!
>>>    }
>>>  }
>>> 
>>>  var accumulator: AccumulatorType? = AccumulatorType()
>>>  accumulator = reduce(into: accumulator.release()) { ... }
>>> 
>>> but then you lose the accumulator if the closure throws.  So, I guess
>>> I'm agreeing with you that the version with the inout accumulator is
>>> more fundamental.
>> 
>> Even if this would work I don’t think it’s a great option.  Accepting an inout accumulator is a far more straightforward programming model with clear performance semantics that don’t require detailed implementation knowledge.
>> 
>>> 
>>> But that's not the only criterion.  Is it as useful and commonly
>>> convenient?  
>> 
>> I would say it is commonly useful.  When it is required it is as convenient as possible.  When an inout accumulator is not required it is admittedly somewhat less convenient.
>> 
>> Whether it is *as* useful and convenient as the proposed variation probably depends on the domain.  Each has their strength with the proposed version probably being a bit more frequently desired.
>> 
>>> If we were to have both versions, how would you name them?
>> 
>> This is a tough question.  The proposed `into:` label makes sense for both the inout accumulator and the proposed variation but I’ll assume overloading won’t be considered for the reasons stated in the proposal.  `intoCopyOf:` would make sense for the proposed copying variation but would penalize it with verbosity and doesn’t copy reference types despite implying that. 
> 
> It seems to me that it isn’t problematic to overload with an `inout` variant. It is always clear to the compiler which to choose based on the presence or lack of a `&` character.


That’s a good point.  Also worth noting is that the in-place mutating variation would probably return `Void`.  If users accidentally omit the `&` sigil the compiler will complain about an unused result because they would not be intending for any result to be available at all.  Maybe we can get away with overloading the `into:` label.

> 
>> The `mutating:` label described in the alternatives considered section of the proposal might might be the best option.  One downside would be if the difference between `into:` and `mutating:` isn't sufficiently clear.  Given that both the types *and* the labels distinct I think it’s probably ok.  The second potential source of confusion would be if using `mutating:` as a label might cause some confusion with mutating methods.  Again, a quick glance at the types reveals that the method is not mutating and the accumulator argument is taken as inout.
>> 
>> What is your thought on using the `into` for the proposed variation and `mutating` for the variation with an inout accumulator?
>> 
>>> 
>>> -- 
>>> -Dave
>>> 
>>> _______________________________________________
>>> 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>
> 
> Cheers,
> Jaden Geller

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170417/d5080f1e/attachment.html>


More information about the swift-evolution mailing list