[swift-evolution] [draft] Introduce Sequence.filteredMap(_:)

Braden Scothern bradenscothern at gmail.com
Mon Oct 23 18:11:25 CDT 2017


The reason `flatMap(_:)` has its name is for code like this:

```
    let nestedArray = [[1, 2, 3], [4, 5, 6]]
    let flatArray = nestedArray.flatMap {
        $0
    }

    print(flatArray) // prints [1, 2, 3, 4, 5, 6]

    let anotherNestedArrays = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]
    let anotherFlatArray = anotherNestedArray.flatMap {
        $0
    }

    print(anotherFlatArray) // prints [[1, 2], [3, 4], [5, 6], [7, 8]]
```

Do your examples from other languages have this behavior of flattening
nested sequences by 1 layer? Do you think it makes sense to have this
effect as part of your proposed rename?

I feel like the name `filteredMap(_:)` implies that the result should keep
the same structure as the original Sequence type which doesn't allow for
the flattening.

If these 2 pieces of functionality weren't already a part of one function
or if you proposal had a good solution to address this other part
functionality, I would be accepting of a name change. I haven't ever been a
fan of flatMap(_:) having 2 jobs, but it has been this way since Swift 1 or
2.


Also, I don't think the name `filterMap` makes sense with Swift naming
conventions. To me it implies that you are going to map in place vs the
filtered makes it clear you are creating a new Array to return. I really
like the sort() vs sorted() naming convention that is already the standard
for Swift code and would rather any name changes stick to that.

On Mon, Oct 23, 2017 at 4:52 PM, Xiaodi Wu via swift-evolution <
swift-evolution at swift.org> 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 at 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 at 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 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
>> swift-evolution at swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>
>>
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution at swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20171023/74b04c4f/attachment.html>


More information about the swift-evolution mailing list