+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> 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> 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 moiseev’s gists · GitHub
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
<0000-introduce-filteredmap.md · GitHub;
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.
<0000-introduce-filteredmap.md · GitHub;
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.
<0000-introduce-filteredmap.md · GitHub
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]
<0000-introduce-filteredmap.md · GitHub
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.
<0000-introduce-filteredmap.md · GitHub
on ABI stability
This is an additive API change, and does not affect ABI stability.
<0000-introduce-filteredmap.md · GitHub
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.
<0000-introduce-filteredmap.md · GitHub
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