Huge +1

Calling "flatMap" a map + filtering out the nil values was a TERRIBLE idea.


Elviro

> Il giorno 24 ott 2017, alle ore 00:15, Max Moiseev via swift-evolution 
> <swift-evolution@swift.org> ha scritto:
> 
> 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 } 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
> 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