Thanks for bringing this up. I've been thinking about this recently, especially in the light of a large number of "trivially composable" proposals that have been brought up recently. The problem is mainly the relative weighting of the criteria we've discussed. Readability improvements and minor performance and correctness optimizations are being used as the main criteria, whereas I feel like major performance wins and really hard (but still relatively common) problems to solve correctly are being underweighted.
I think there's a real risk with the current pitches that we end up with a standard library populated with huge quantities of sugar and not enough protein. I feel like we need to refocus on key algorithms that are important and hard to write correctly, rather than minor nice-to-haves which are (sometimes) more common, but also very easily written. A standard library that is missing stable sorting and partitioning, rotation, permutation, and binary search, but does have notEmpty
, id
, isEven
, would be pretty unfortunate.
I see this as guidance when adding something about what to call it, and not guidance as to what to add. That is, once you have decided to add an allSatisfies
method, that naming guidance is how you decide to call it that and not all
or contains(only:)
. It isn't an encouragement to add synonyms or trivially composable methods to the standard library. Those can sometimes aid readability – but they harm the usability of the library by bloating it, making it hard to use and navigate.
I think there's an important difference. The motivation for toggle was the need to duplicate long expressions (path.to.something.over.here = !path.to.something.over.here
) as well as avoid the risk of typos in that long expression. Neither of these arguments materially apply to !isEmpty
over notEmpty
.