Given the existence of filter already, I submit that filterMap is 
somewhat overloaded and users would expect that, like flatMap, it would map 
over all elements and then filter based on some predicate. While that’s awkward 
to express and likely isn’t useful enough to be in the standard library, to 
have it just handle nils would seem unexpected to anyone who hadn’t read the 
signature when finding it in the autocomplete list or reading in documentation. 
That why I like compact. It’s currently unused in Swift, so it can be given 
whatever meaning we want, and it coincides with Ruby’s use of it, meaning 
there’s at least some precedent for using it to remove nils.



Jon

> On Nov 15, 2017, at 9:58 PM, John McCall via swift-evolution 
> <swift-evolution@swift.org> wrote:
> 
>> 
>> On Nov 15, 2017, at 9:16 PM, Greg Parker <gpar...@apple.com 
>> <mailto:gpar...@apple.com>> wrote:
>> 
>> 
>>> On Nov 15, 2017, at 5:53 PM, John McCall <rjmcc...@apple.com 
>>> <mailto:rjmcc...@apple.com>> wrote:
>>> 
>>>> On Nov 15, 2017, at 7:36 PM, Greg Parker via swift-evolution 
>>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>>>> 
>>>>> On Nov 15, 2017, at 2:31 PM, BJ Homer via swift-evolution 
>>>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>>>>> 
>>>>>> On Nov 15, 2017, at 3:05 PM, Tino Heth via swift-evolution 
>>>>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>>>>>> 
>>>>>> Odd… exactly that is the reason why I think filterMap is the worst 
>>>>>> choice:
>>>>>> 
>>>>>> Both are established terms of art, but one has a meaning that doesn’t 
>>>>>> fit to the operation.
>>>>>> Applying filter can remove elements, but it can never change types (I 
>>>>>> feel kind of silly to repeat this over and over, but so far, nobody took 
>>>>>> the time to falsify this).
>>>>> 
>>>>> The concern about filter changing types is only relevant if you think of 
>>>>> the filter applying to the result of the map, instead of being a part of 
>>>>> the filterMap operation itself (an operation that is distinct from map).
>>>>> 
>>>>> Let’s imagine that we had this instead:
>>>>> 
>>>>> enum SelectiveMapResult<T> {
>>>>>     case use(T)
>>>>>     case ignore
>>>>> }
>>>>> 
>>>>> extension Sequence {
>>>>>     func selectiveMap<T>(_ selectiveTransform: 
>>>>> (Element)->SelectiveMapResult<T>) -> [T]
>>>>> }
>>>>> 
>>>>> let actualNumbers =
>>>>>     ["1", "2", "apple", "banana", "5"].selectiveMap({ 
>>>>> (x)->SelectiveMapResult<Int> in
>>>>>         if let value = Int(x) { return .use(value) }
>>>>>         else { return .ignore }
>>>>>     })
>>>>> 
>>>>> actualNumbers == [1, 2, 5]
>>>>> 
>>>>> The “selective” part of this operation doesn’t feel like it’s changing 
>>>>> the type of the result, because SelectiveMapResult is easily understood 
>>>>> to not be part of the mapping transformation; it just exists to tell us 
>>>>> whether we should use the result of that particular transformation. 
>>>>> Likewise, I don’t feel like the optional in filterMap is part of the 
>>>>> mapping operation; it’s just serving the same role as SelectiveMapResult. 
>>>>> (It should be obvious that SelectiveMapResult is just Optional with 
>>>>> another name here.)
>>>> 
>>>> "selectiveMap" feels better in part due to grammar. "map" is obviously the 
>>>> verb and "selective" is obviously a modification of "map". "selectiveMap" 
>>>> is therefore performing some sort of special map operation. 
>>>> 
>>>> "filterMap" feels bad for the same reason that "selectMap" would feel 
>>>> worse than "selectiveMap". "filter" and "map" are both verbs in this 
>>>> context. Grammatically the analogue to "selectiveMap" would be 
>>>> "filteredMap" or "filteringMap". 
>>>> 
>>>> But even then "filteredMap" or "filteringMap" is insufficient to describe 
>>>> the operation. You additionally need to know that the "filter" here is not 
>>>> ordinary "filter", but instead the special case "filter { $0 != nil }".
>>>> 
>>>> 
>>>>> The name filterMap focuses on removing the ignored values, as does 
>>>>> compactMap. The name selectiveMap focuses on retaining the non-ignored 
>>>>> values. I’m not sure whether focusing on the positive or negative aspects 
>>>>> is clearer here. I don’t particularly like the name compactMap, simply 
>>>>> because I don’t have a lot of experience with languages that use 
>>>>> “compact” to mean “drop the nil values”, and without that experience it 
>>>>> doesn’t seem intuitive. I think filterMap is better. But if we introduced 
>>>>> Sequence.compact() alongside .compactMap(), I’d probably get used to it.
>>>> 
>>>> Swift doesn't use "filter" to mean "drop the nil values" either. 
>>>> 
>>>> 
>>>> "compactMap" is okay if "compact" is added. Is "compact" a common enough 
>>>> operation in practice to pull its own weight?
>>>> 
>>>> "mapSome" is great if you know about Optional.Some but terrible if you 
>>>> don't. ("Okay, it maps some elements, but which ones?") 
>>>> 
>>>> "mapNonNil" is obvious and ugly and perhaps its obviousness makes it a 
>>>> winner.
>>> 
>>> mapSome and especially mapNonNil both sound to me like they only map the 
>>> non-nil values in the source sequence.
>> 
>> I thought it did map the non-nil values in the source sequence. Did I 
>> misunderstand what the proposed filterMap does? It occurs to me that the 
>> proposal does not have a standalone description of the filterMap operation.
> 
> func filterMap<T>(_ f: (Element) -> T?) -> [T] {
>   return self.map(f).filter { $0 != nil }.map( $0! } // not an efficient 
> implementation
> }
> 
> A mapping function is applied to all elements of the source sequence.  Unlike 
> map, however, the mapping function can return nil, causing that value to be 
> dropped from the result sequence.  Since the result sequence can therefore 
> not contain any (directly) nil values, a level of optionality is removed from 
> the result element type.  A common use case — perhaps the most common — is to 
> simultaneously map and filter a sequence without introducing any unnecessary 
> intermediate sequences, which is why it is often called filterMap in 
> functional languages.
> 
> John.
> _______________________________________________
> 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