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 <xiaodi...@gmail.com> 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 
> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> 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 
>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> 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 
>> <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 : Sequence
>> Optional.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 
>> <http://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
>> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
>> https://lists.swift.org/mailman/listinfo/swift-evolution 
>> <https://lists.swift.org/mailman/listinfo/swift-evolution>
> 
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
> https://lists.swift.org/mailman/listinfo/swift-evolution 
> <https://lists.swift.org/mailman/listinfo/swift-evolution>

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to