on Sun Jun 26 2016, Erica Sadun <erica-AT-ericasadun.com> wrote: >> On Jun 26, 2016, at 10:35 AM, Dave Abrahams <dabrah...@apple.com> wrote: >> >> >> on Sat Jun 25 2016, Erica Sadun <erica-AT-ericasadun.com >> <http://erica-at-ericasadun.com/>> wrote: > >> >>> On Jun 25, 2016, at 4:25 PM, Dave Abrahams <dabrah...@apple.com> 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@swift.org> wrote: >>>>> >>>>> - 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. >>> >>> When using a procedural "trailable" closure inside parentheses, the >>> intention >>> to do so should be clear: >>> >>> p(x, perform: {...}) >>> p(x, do: {...}) >>> >>> vs >>> >>> p(x) { >>> ... >>> } >>> >>> Anyone reading this code can immediately identify that an otherwise trailing >>> closure has been pulled inside the signature because the call has become >>> significantly more complex. The point-of-coding decision ripples through >>> to point-of-reading/point-of-maintenance. >>> >>>>> 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 read through the pull request. I grouped related modifications >>> together, although not exhaustively. They fall under the same umbrella, >>> choosing `do` or `perform` compared to `invoke` or `invoking`. >>> >>> - _forAllPermutationsImpl(index + 1, size, &perm, &visited, body) >>> + _forAllPermutationsImpl(index + 1, size, &perm, &visited, invoke: body) >>> >>> -public func runRaceTest(trials: Int, threads: Int? = nil, body: () -> ()) { >>> +public func runRaceTest( >>> + trials: Int, threads: Int? = nil, invoking body: () -> () >>> +) { >>> >>> -public func expectFailure(${TRACE}, body: () -> Void) { >>> +public func expectFailure(${TRACE}, invoking body: () -> Void) { >> >> OK, I understand your process now. I still don't understand your >> rationale for saying `do` or `perform` is better than `invoke`. Or is >> it just personal taste? > > See below. But in a nutshell, `do` gets the idea across. It's short. It's > pithy. > It uses a common, comfortable word. So yes, personal taste. But it's personal > taste backed up by some statistics.
I get the reasons for `do`; I can't understand how `perform` might be an improvement over `invoke`. >>>>> 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. >>> >>> You did, as in the examples just above, which you recommend a rename to >>> `invoke` or >>> `invoking`. >> >> Ah, thanks. >> >>>>> -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? >>> >>> Strong personal taste, backed by tech writing. Simpler words. >>> From the Corpus of Contemporary American English: >>> do: 18 >>> perform: 955 >>> invoke: does not appear on list. >> >> I'm unable to reproduce those numbers using >> http://corpus.byu.edu/coca/ <http://corpus.byu.edu/coca/>. >> What exactly did you do to get them? > > I used a secondary webpage that rates word frequency based on the COCA corpus: > http://www.wordfrequency.info/free.asp?s=y > >> Also, I'm not sure commonality of use is a good rationale. I bet >> “function” doesn't appear as often as “task” either, but the argument >> here is a function and we invoke functions. Sometimes the appropriate >> word is just less common. > > 1051 task > 1449 function > > Numbers aside, there's always a "term of art" argument to be made. A term of > art is precise and instantly communicates the meaning to the user. > > I don't think a "term of art" argument can be made here since invoke, > perform, and do all communicate the same idea to the end-coder, who > doesn't need to know exactly how the compiler sees the argument. > > In naming theory, I'd say the member name carries the greatest weight > when using exact terms and that internal labels should accessorize the > primary name. When using a "term of art" argument, it should apply > most strongly to a method/function/ property/type name and less to > supporting external labels. > >>>>> - return IteratorSequence(it).reduce(initial, combine: f) >>>>> + return IteratorSequence(it).reduce(initial, accumulatingBy: f) >>>>> >>>>> For `reduce`, I'd prefer `applying:` or `byApplying:` >>>> >>>> Makes sense. >>>> >>>>> Similarly in `starts(with:comparingBy:)`, I'd prefer byComparing`, >>>> >>>> I don't see how that works. You're not comparing the closure with >>>> anything. >>> >>> I get your point but I think it's unnecessarily fussy. >> >> I plead guilty to sometimes having unnecessarily fussy tendencies, but >> in this case I believe strongly that “byComparing” would be actively >> misleading and harmful. Even if there's only one possible sane >> interpretation, if readers have to scratch their heads and do an >> exhaustive search through possible interpretations of what something >> might mean because the one directly implied by the grammar is nonsense, >> that's bad. > > "Comparing by" is not actively misleading or harmful but it does sound > strained. Absolutely. > I think a well-designed language should use comfortable constructs.Why > not use a single , plain word that describes a parameter's role. Why > not "compare:"? It's far less fussy and it's clear. Yes, we can do that at the cost of fluency. Fluency isn't everything. >>> Alternatives are slim on the ground. `usingComparison:` is too long, >>> as is `byComparingWith:` (which still reads better but you will point >>> out can be mistaken by some pedant to mean that the sequence is being >>> compared to the closure), and you won't allow for `comparing:`. I'm >>> not in love with `comparingWith:` but it reads slightly better to me >>> than `comparingBy:`. >> >> There is definitely something awkward about “xxxBy:” for these uses, and >> I'm open to using “xxxWith:” instead, even though as you say it's >> confusable. >> >> if x.starts(with: y, comparingBy: { $0.name == $1.name }) { >> ... >> } >> >> if x.starts(with: y, comparingWith: { $0.name == $1.name }) { >> ... >> } >> >> At some point I start to wonder if giving up fluency is best: >> >> if x.starts(with: y, equality: { $0.name == $1.name }) { >> ... >> } > > Yes. `predicate`, `compare` (or `comparison`), `order:`, etc. > > To riff off Gerard Manley Hopkins, "Glory be for simple things, for > short words and trim APIs". > >>>>> min/max, byOrdering >>>> >>>> Likewise, you're not ordering the closure. >>> >>> Same reasoning. >>> >>>> >>>>> - ).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.” >>> >>> For a language that treasures concision and clarity, this may be clear >>> but it's notably inconcise. (Yes, that is a new word.) >> >> I agree, but if you want concision I'd rather stick with something that >> doesn't imply anything unintended, such as “to” or “into.” > > I much prefer `to` and `into` > >>>>> - 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}) >>> >>> But they're sorting now, and that feature isn't in Swift. >> >> That doesn't mean we should claim the syntax for another purpose. >> I think we probably do want that feature eventually. >> >>> However, `sorted` falls under another umbrella, which is potential >>> chaining. In such case, I would prefer there be no internal label at all >>> to allow cleaner functional flow. >> >> IMO whether a method has a non-Void return value (and thus is chainable) >> should not be the determining feature on whether we use argument labels. > > If any method returns a sequence or collection, I think it *should* be > considered in that specific light as a candidate for chaining. I agree > that expanding that to any return value is too wide. > >> We *could* decide to drop all labels for trailing closures (on the >> grounds that they often won't appear at the call site) and say the >> policy is that if there's something you want to communicate about the >> closure's role, you simply do the best you can with the parameter name >> and let the clarity at the call site fend for itself. That, at least, >> would be a reasonably principled approach. > > I like labels for trailing closures when they are `-> Void`. You know a > priori > that the closure is used for side-effects, so if they are put into a function > or > method call, the label alerts you to design intent. > > I want to omit labels for trailing closures when they return collections, > sequences, > iterators, etc. because these return types are most likely to be chained. > > If you force a label for, say, map, people will choose > > map { ... } > > over > > map(label: { ... }) > > because the former reads better, especially when chaining but it introduces > bad habits, because it will not compile when used with constructs like: > > for i in map { ... } { // will not compile > ... > } I don't think Swift wants to buy into the idea that using map without trailing closures is a bad habit. We strongly believe in trailing closure syntax. I would much rather find ways to make the syntax above legal. Furthermore, the logic doesn't follow for me. There are other ways to get that to compile, such as for i in (map { ... }) { // will not compile Why not make the argument that it's a bad habit to call map without *surrounding* parentheses? > But if you treat collection/sequence fp as "highly likely to be > chained", it encourages > results more like: > > for i in x.map({ ...}).filter({ ... }) { > .... > } > > which is compiler-safe, more readable, etc, especially for very > short-form items like: > > for var i in x.flatMap({Int($0)}).filter({ $0 < 10 }) { I disagree about readability. One set of surrounding parentheses is clearer for var i in (x.flatMap{ Int($0) }.filter{ $0 < 10 }) { Further, I am concerned about pervasive inefficiency when people try to pack this kind of chaining into a for loop with as few characters as possible. Generally speaking, it would be better to do it lazily. >>> Functional programming flow. I follow Kevin Ballard's rule of parens around >>> functional elements and naked braces for trailing closures that do not >>> return >>> values. This ensures the compiler is never confused at places like: >>> >>> for x in foo when y.f{...} { >>> ... >>> } >> >> ? It's never confused there; it tells you it's illegal. >> >>> and instantly identifies to the reader when there's a non-returning scope, >>> as >>> in forEach or GCD dispatch. >> >> Why is it useful to identify when there's a scope that doesn't return a >> value? Isn't that already clear from whether the value is assigned >> somewhere? > > Enhanced readability from explicit coding intent. Trailing closures > *look* like a scope created by a native construct. Those enclosed in > parens *look* like arguments. I understand what you're saying, but I think it's unnecessarily fussy ;-) two-can-play-at-that-game-ly y'rs, -- -Dave _______________________________________________ swift-evolution mailing list swift-evolution@swift.org https://lists.swift.org/mailman/listinfo/swift-evolution