+1 good idea. Re. the naming I would suggest `mapFilterNil` since it says what it does and filter, nil, and map are all understood already in Swift. (I have sympathy for people wanting `mapFilteringNil`, but Swift chose `filter`.)
The problems I see with `filterMap` are that: 1. It sounds like it is a merged `filter` and `map` and therefore you would expect it to have two arguments, one to filter and one to map, i.e. `filterMap<R>(filter: (T) -> Bool, map: (T) -> R) -> [R]`. 2. It sounds like it will filter the incoming values (for `nil`, but see 1 above) and then map, i.e. `filterMap<R>(map: (T?) -> R) -> [R]`, note `T?` *not* `R?`. -- Howard. On 24 October 2017 at 11:56, BJ Homer via swift-evolution < [email protected]> wrote: > I agree with Xiaodi; I like ‘filterMap’ more than ‘filteredMap’. But both > are superior to ‘flatMap’ in this context. > > -BJ > > On Oct 23, 2017, at 5:22 PM, Max Moiseev <[email protected]> wrote: > > It occurred to me that filteringMap(_:) should be even more descriptive, > still conform to the guidelines, although similarly unprecedented and > un-googlable. > > Max > > On Oct 23, 2017, at 3:52 PM, Xiaodi Wu <[email protected]> wrote: > > +1 in general. As to the name: since 'map' is used as a term of art, > 'filterMap' seems superior to 'filteredMap', which half follows naming > guidelines and half is a term of art; neither is immediately comprehensible > but 'filterMap' can be googled and has precedents in other languages. > On Mon, Oct 23, 2017 at 17:24 BJ Homer via swift-evolution < > [email protected]> wrote: > >> I strongly agree! In fact, I just started writing up a similar proposal >> the other day, but hadn’t had time to finish it yet. >> >> The current name for this particular filtering variant is not >> particularly descriptive. It’s certainly not obvious to newcomers that >> ‘flatMap’ will filter out results. And it’s not true to the existing usage >> of ‘flatMap' from other languages; you have to really squint at it to see >> how any “flattening” is happening at all. >> >> So yes, a big +1 from me. Thanks! >> >> -BJ Homer >> >> On Oct 23, 2017, at 4:15 PM, Max Moiseev via swift-evolution < >> [email protected]> wrote: >> >> Hi swift-evolution! >> >> I would like to propose the following change to the standard library: >> >> deprecate `Sequence.flatMap<U>(_: (Element) -> U?) -> [U]` and make this >> functionality available under a new name `Sequence.filteredMap(_:)`. >> >> The draft is available at https://gist.github.com/moiseev/ >> 2f36376c8ef4c2b1273cff0bfd9c3b95 and is included below for your >> convenience. >> >> Max >> >> Introduce Sequence.filteredMap(_:) >> >> - Proposal: SE-NNNN <https://gist.github.com/moiseev/NNNN-filename.md> >> - Authors: Max Moiseev <https://github.com/moiseev> >> - Review Manager: TBD >> - Status: Awaiting implementation >> >> >> <https://gist.github.com/moiseev/2f36376c8ef4c2b1273cff0bfd9c3b95#introduction> >> Introduction >> >> We propose to deprecate the controversial version of a Sequence.flatMap >> method >> and provide the same functionality under a different, and potentially more >> descriptive, name. >> >> <https://gist.github.com/moiseev/2f36376c8ef4c2b1273cff0bfd9c3b95#motivation> >> Motivation >> >> The Swift standard library currently defines 3 distinct overloads for >> flatMap: >> >> Sequence.flatMap<S>(_: (Element) -> S) -> [S.Element] >> where S : SequenceOptional.flatMap<U>(_: (Wrapped) -> U?) -> >> U?Sequence.flatMap<U>(_: (Element) -> U?) -> [U] >> >> The last one, despite being useful in certain situations, can be (and >> often is) misused. Consider the following snippet: >> >> struct Person { >> var age: Int >> var name: String >> } >> func getAges(people: [Person]) -> [Int] { >> return people.flatMap { $0.age } >> } >> >> What happens inside getNames is: thanks to the implicit promotion to >> Optional, the result of the closure gets wrapped into a .some, then >> immediately unwrapped by the implementation of flatMap, and appended to >> the result array. All this unnecessary wrapping and unwrapping can be >> easily avoided by just using map instead. >> >> func getAges(people: [Person]) -> [Int] { >> return people.map { $0.age } >> } >> >> It gets even worse when we consider future code modifications, like the >> one where Swift 4 introduced a Stringconformance to the Collection protocol. >> The following code used to compile (due to the flatMap overload in >> question). >> >> func getNames(people: [Person]) -> [String] { >> return people.flatMap { $0.name } >> } >> >> But it no longer does, because now there is a better overload that does >> not involve implicit promotion. In this particular case, the compiler error >> would be obvious, as it would point at the same line where flatMap is >> used. Imagine however if it was just a let names = people.flatMap { $ >> 0.name } statement, and the names variable were used elsewhere. The >> compiler error would be misleading. >> >> <https://gist.github.com/moiseev/2f36376c8ef4c2b1273cff0bfd9c3b95#proposed-solution>Proposed >> solution >> >> We propose to deprecate the controversial overload of flatMap and >> re-introduce the same functionality under a new name. The name being >> filteredMap(_:) as we believe it best describes the intent of this >> function. >> >> For reference, here are the alternative names from other languages: >> >> - Haskell, Idris mapMaybe :: (a -> Maybe b) -> [a] -> [b] >> - Ocaml (Core and Batteries) filter_map : 'a t -> f:('a -> 'b >> option) -> 'b t >> - F# List.choose : ('T -> 'U option) -> 'T list -> 'U list >> - Rust fn filter_map<B, F>(self, f: F) -> FilterMap<Self, F> where >> F: FnMut(Self::Item) -> Option<B> >> - Scala def collect[B](pf: PartialFunction[A, B]): List[B] >> >> >> <https://gist.github.com/moiseev/2f36376c8ef4c2b1273cff0bfd9c3b95#source-compatibility>Source >> compatibility >> >> Since the old function will still be available (although deprecated) all >> the existing code will compile, producing a deprecation warning and a >> fix-it. >> >> <https://gist.github.com/moiseev/2f36376c8ef4c2b1273cff0bfd9c3b95#effect-on-abi-stability>Effect >> on ABI stability >> >> This is an additive API change, and does not affect ABI stability. >> >> <https://gist.github.com/moiseev/2f36376c8ef4c2b1273cff0bfd9c3b95#effect-on-api-resilience>Effect >> on API resilience >> >> Ideally, the deprecated flatMap overload would not exist at the time >> when ABI stability is declared, but in the worst case, it will be available >> in a deprecated form from a library post-ABI stability. >> >> <https://gist.github.com/moiseev/2f36376c8ef4c2b1273cff0bfd9c3b95#alternatives-considered>Alternatives >> considered >> >> It was attempted in the past to warn about this kind of misuse and do the >> right thing instead by means of a deprecated overload with a >> non-optional-returning closure. The attempt failed due to another implicit >> promotion (this time to Any). >> >> The following alternative names for this function were considered: >> >> - mapNonNil(_:) Does not communicate what happens to nil’s >> - mapSome(_:) Reads more like «map some elements of the sequence, >> but not the others» rather than «process only the ones that produce an >> Optional.some» >> - filterMap(_:) Does not really follow the naming guidelines and >> doesn’t seem to be common enough to be considered a term of art. >> >> >> _______________________________________________ >> swift-evolution mailing list >> [email protected] >> https://lists.swift.org/mailman/listinfo/swift-evolution >> >> >> _______________________________________________ >> swift-evolution mailing list >> [email protected] >> https://lists.swift.org/mailman/listinfo/swift-evolution >> > > > _______________________________________________ > swift-evolution mailing list > [email protected] > https://lists.swift.org/mailman/listinfo/swift-evolution > >
_______________________________________________ swift-evolution mailing list [email protected] https://lists.swift.org/mailman/listinfo/swift-evolution
