[swift-evolution] Stdlib closure argument labels and parameter names
David Hart
david at hartbit.com
Sat Jun 25 18:56:26 CDT 2016
Comments inline:
Sent from my iPhone
> On 26 Jun 2016, at 00:25, Dave Abrahams via swift-evolution <swift-evolution at swift.org> wrote:
>
>
>> on Wed Jun 22 2016, Erica Sadun <erica-AT-ericasadun.com> wrote:
>>
>>> On Jun 20, 2016, at 3:25 PM, Dave Abrahams via swift-evolution <swift-evolution at swift.org> wrote:
>>>
>>>
>>> Hi All,
>>>
>>> A couple of weeks ago we started to notice that we had some poorly-named
>>> closure parameters and argument labels in the standard library, so we
>>> did a complete audit of the standard library's APIs and came up with a
>>> preliminary proposal for changes, which we applied in a branch and you
>>> can review in https://github.com/apple/swift/pull/2981. Let's please
>>> carry on further discussion here rather than in the pull request, though.
>>
>> - /// - `isEquivalent(a, a)` is always `true`. (Reflexivity)
>> - /// - `isEquivalent(a, b)` implies `isEquivalent(b, a)`. (Symmetry)
>> - /// - If `isEquivalent(a, b)` and `isEquivalent(b, c)` are both `true`, then
>> - /// `isEquivalent(a, c)` is also `true`. (Transitivity)
>> + /// - `areEquivalent(a, a)` is always `true`. (Reflexivity)
>> + /// - `areEquivalent(a, b)` implies `areEquivalent(b, a)`. (Symmetry)
>> + /// - If `areEquivalent(a, b)` and `areEquivalent(b, c)` are both `true`, then
>> + /// `areEquivalent(a, c)` is also `true`. (Transitivity)
>>
>> I like this change!
>>
>> - func forEach<S: SequenceType>(_ body: (S.Iterator.Element) -> ())
>> + func forEach<S: SequenceType>(invoke body: (S.Iterator.Element) -> ())
>>
>> Adding an external label makes sense here. This is a procedural call and
>> using it within the parens should have a "code ripple".
>
> I don't think I understand what you mean here.
>
>> That said, would prefer `do` or `perform` over `invoke` or `invoking` as in
>> `runRaceTest`, `_forAllPermutationsImpl`, `expectFailure`, etc.
>
> Sorry, again, I'm a little lost. Forgive my overly-literal brain but
> could you please spell out how those latter 3 names relate to the choice
> of `do` or `perform` over `invoke`?
I'd vote for `do`, just to keep those functional method labels short.
>> This also applies where there's a `body` label instead of an empty
>> external label.
>
> We don't have any methods with a `body` label IIUC.
>
>> -public func withInvalidOrderings(_ body: ((Int, Int) -> Bool) -> Void) {
>> +public func withInvalidOrderings(invoke body: ((Int, Int) -> Bool) -> Void) {
>>
>> For any with/external label pair, I'd prefer `with-do` or `with-perform`
>> over `with-invoke`.
>
> OK. Is there a rationale, or is it just personal taste?
>
>> - return IteratorSequence(it).reduce(initial, combine: f)
>> + return IteratorSequence(it).reduce(initial, accumulatingBy: f)
>>
>> For `reduce`, I'd prefer `applying:` or `byApplying:`
>
> Makes sense.
`applying` looks great. The `by` looks redundant in this case.
>> Similarly in `starts(with:comparingBy:)`, I'd prefer byComparing`,
>
> I don't see how that works. You're not comparing the closure with
> anything.
>> min/max, byOrdering
>
> Likewise, you're not ordering the closure.
I agree with you Dave on both of those.
>
>> - ).encode(encoding, output: output)
>> + ).encode(encoding, sendingOutputTo: processCodeUnit)
>>
>> How about `exportingTo`?
>
> “export” is freighted with various connotations that I don't think we
> want to make here. In fact it doesn't mean anything more exotic than
> “sending output to.”
>
>> - tempwords.sort(isOrderedBefore: <)
>> + tempwords.sort(orderingBy: <)
>>
>> With `sort` and `sorted`, I'd prefer `by:`
>
> When people talk about “sorting by XXX”, XXX is a property of the
> elements being sorted. Therefore IMIO that label should probably be
> reserved for a version that takes a unary projection function:
>
> friends.sort(by: {$0.lastName})
How about `sort(with:)` then?
>
>> - if !expected.elementsEqual(actual, isEquivalent: sameValue) {
>> + if !expected.elementsEqual(actual, comparingBy: sameValue) {
>>
>> I'm torn on this one. I don't like but I don't have a good solution.
>>
>> - /// for which `predicate(x) == true`.
>> + /// for which `isIncluded(x) == true`.
>> - _base: base.makeIterator(), whereElementsSatisfy: _include)
>> + _base: base.makeIterator(), suchThat: _include)
>>
>> How about simply `include` for both?
>
> Looking at the effect on the doc comments—which is how we should judge
> parameter names—I think `predicate` might read better.
>
>> I get the `is` desire but it's being tossed away in a lot of other
>> places in this diff. and `suchThat` feels out of place.
>
> I think I'm pretty strongly sold on “soEach” as a label for closures in
> all the filtering components.
>
>> - || u16.contains({ $0 > 127 || _isspace_clocale($0) }) {
>> + || u16.contains(elementWhere: { $0 > 127 || _isspace_clocale($0) }) {
>>
>> I assume the challenge here is differentiating contains(element) from contains(closure).
>> This feels predicate-y, which is why I put it near the predicates. But I think something
>> like `containsElement(where:)` works better.
>
> I understand your motivation for suggesting it. The downside is that it
> severs the strong basename relationship between algorithms that do
> effectively the same things, one using a default comparison and the
> other using an explicitly-specified one. I'm truly not sure where we
> ought to land on this one.
I agree with Dave, the algorithms do the same thing, but with different arguments. I think we'd loose discoverability if we applied Erica's proposition.
>> - let result = try base._withUnsafeMutableBufferPointerIfSupported(body)
>> + let result = try base._withUnsafeMutableBufferPointerIfSupported(invoke: body)
>>
>> I hate "ifSupported"
>
> Me too.
>
>> but that's another discussion
>
> Quite. It's also an internal API so it's not an evolution issue. The
> point of having that change as part of the diff (as with all the other
> use sites), is to observe how the changes affect real usage.
>
>> (withSupportedUnsafeMutableBufferPointer,
>> withAvailableUnsafeMutableBufferPointer, it's all lipstick)
>>
>> This is procedural, so `do` or `perform` rather than `invoke`
>>
>> - for test in removeFirstTests.filter({ $0.numberToRemove == 1 }) {
>> + for test in removeFirstTests.filter(
>> + suchThat: { $0.numberToRemove == 1 }
>>
>> The difference between `filter` and `forEach` is that `forEach` is explicitly
>> procedural while `filter` is functional. I do not like functional chainable
>> calls being modified to use explicit external labels in this way.
>>
>> I'd prefer no label here.
>
> Can you provide rationale for treating functional methods differently,
> or is it just personal taste?
>
>> public func split(
>> maxSplits: Int = Int.max,
>> omittingEmptySubsequences: Bool = true,
>> - isSeparator: @noescape (Base.Iterator.Element) throws -> Bool
>> + separatedWhere isSeparator: @noescape (Base.Iterator.Element) throws -> Bool
>>
>> I'm torn on this one. It's not the worst ever but something more like where/at/when
>> makes more sense to me than
>> "separatedWhere/separatedAt/separatedWhen".
>
> The biggest reason to keep “separate” in the name is the connection with
> the semantics of the other `split` method, that takes a single element
> that is tested for equality. I think this is very similar to the
> `contains(elementWhere` vs `containsElement(where` discussion. If you
> leave “separate” out of the name it fails to imply that those elements
> for which the predicate returns true are not present in the result.
>
>>
>> + count: __manager._headerPointer.pointee.count)
>>
>> For the sake of Zippy the Pinhead, surely there has to be something better than `pointee`.
>> Like...`reference`?
>
> It's not a reference; it's a value. But that, my friend, is an
> *entirely* different discussion. Let's try to stick to the scope of the
> proposal: names and labels for parameters of function type, OK?
>
> --
> -Dave
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
More information about the swift-evolution
mailing list