<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class=""><span class="Apple-tab-span" style="white-space:pre">        </span>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.<div class=""><br class=""></div><div class=""><br class=""></div><div class=""><br class=""></div><div class="">Jon<br class=""><div><br class=""><blockquote type="cite" class=""><div class="">On Nov 15, 2017, at 9:58 PM, John McCall via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><blockquote type="cite" class=""><div class=""><br class="Apple-interchange-newline">On Nov 15, 2017, at 9:16 PM, Greg Parker <<a href="mailto:gparker@apple.com" class="">gparker@apple.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;"><br class=""><div class=""><blockquote type="cite" class=""><div class="">On Nov 15, 2017, at 5:53 PM, John McCall <<a href="mailto:rjmccall@apple.com" class="">rjmccall@apple.com</a>> wrote:</div><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;"><br class=""><div class=""><blockquote type="cite" class=""><div class="">On Nov 15, 2017, at 7:36 PM, Greg Parker via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> wrote:</div><div class=""><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><blockquote type="cite" class=""><div class=""></div></blockquote></div></div></blockquote><blockquote type="cite" class=""><div class=""><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><blockquote type="cite" class=""><div class=""></div></blockquote></div></div></blockquote></div></div></div></blockquote><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;"><div class=""><blockquote type="cite" class=""><div class=""><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><blockquote type="cite" class=""><div class=""><br class="Apple-interchange-newline"></div></blockquote></div></div></blockquote></div></div></div><blockquote type="cite" class=""><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;"><div class=""><blockquote type="cite" class=""><div class=""><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><blockquote type="cite" class=""><div class="">On Nov 15, 2017, at 2:31 PM, BJ Homer via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> wrote:</div><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space;"><br class=""><div class=""><blockquote type="cite" class=""><div class="">On Nov 15, 2017, at 3:05 PM, Tino Heth via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> wrote:</div><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space;"><div class=""><br class=""></div>Odd… exactly that is the reason why I think filterMap is the worst choice:</div></div></blockquote><blockquote type="cite" class=""><br class=""></blockquote><blockquote type="cite" class=""><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space;"><div class="">Both are established terms of art, but one has a meaning that doesn’t fit to the operation.</div><div class="">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).</div></div></div></blockquote></div><br class=""><div class="">The concern about<span class="Apple-converted-space"> </span><font face="Menlo" class="">filter</font><span class="Apple-converted-space"> </span>changing types is only relevant if you think of the filter applying to the<span class="Apple-converted-space"> </span><i class="">result</i> of the map, instead of being a part of the<span class="Apple-converted-space"> </span><font face="Menlo" class="">filterMap</font><span class="Apple-converted-space"> </span>operation itself (an operation that is distinct from<span class="Apple-converted-space"> </span><font face="Menlo" class="">map</font>).</div><div class=""><br class=""></div><div class="">Let’s imagine that we had this instead:</div><div class=""><br class=""></div><blockquote class="" style="margin: 0px 0px 0px 40px; border: none; padding: 0px;"><div class=""><div class="" style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo; background-color: rgb(255, 255, 255);"><span class="" style="font-size: 11px;"><span class="" style="color: rgb(186, 45, 162);">enum</span><span class="Apple-converted-space"> </span>SelectiveMapResult<T> {</span></div></div><div class=""><div class="" style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo; background-color: rgb(255, 255, 255);"><span class="" style="font-size: 11px;"> <span class="Apple-converted-space"> </span><span class="" style="color: rgb(186, 45, 162);">case</span><span class="Apple-converted-space"> </span>use(<span class="" style="color: rgb(79, 129, 135);">T</span>)</span></div></div><div class=""><div class="" style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo; background-color: rgb(255, 255, 255);"><span class="" style="font-size: 11px;"> <span class="Apple-converted-space"> </span><span class="" style="color: rgb(186, 45, 162);">case</span><span class="Apple-converted-space"> </span>ignore</span></div></div><div class=""><div class="" style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo; background-color: rgb(255, 255, 255);"><span class="" style="font-size: 11px;">}</span></div></div><div class=""><div class="" style="margin: 0px; font-stretch: normal; line-height: normal; background-color: rgb(255, 255, 255); min-height: 14px;"><span class="" style="font-size: 11px;"><br class=""></span></div></div><div class=""><div class="" style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo; color: rgb(186, 45, 162); background-color: rgb(255, 255, 255);"><span class="" style="font-size: 11px;">extension<span class=""><span class="Apple-converted-space"> </span></span><span class="" style="color: rgb(112, 61, 170);">Sequence</span><span class=""><span class="Apple-converted-space"> </span>{</span></span></div></div><div class=""><div class="" style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo; background-color: rgb(255, 255, 255);"><span class="" style="font-size: 11px;"> <span class="Apple-converted-space"> </span><span class="" style="color: rgb(186, 45, 162);">func</span><span class="Apple-converted-space"> </span>selectiveMap<T>(<span class="" style="color: rgb(186, 45, 162);">_</span><span class="Apple-converted-space"> </span>selectiveTransform: (<span class="" style="color: rgb(112, 61, 170);">Element</span>)-><span class="" style="color: rgb(79, 129, 135);">SelectiveMapResult</span><<span class="" style="color: rgb(79, 129, 135);">T</span>>) -> [<span class="" style="color: rgb(79, 129, 135);">T</span>]</span></div></div><div class=""><div class="" style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo; background-color: rgb(255, 255, 255);"><span class="" style="font-size: 11px;">}</span></div></div><div class=""><div class="" style="margin: 0px; font-stretch: normal; line-height: normal; background-color: rgb(255, 255, 255); min-height: 14px;"><span class="" style="font-size: 11px;"><br class=""></span></div></div><div class=""><div class="" style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo; background-color: rgb(255, 255, 255);"><span class="" style="font-size: 11px;"><span class="" style="color: rgb(186, 45, 162);">let</span><span class="Apple-converted-space"> </span>actualNumbers =</span></div></div><div class=""><div class="" style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo; background-color: rgb(255, 255, 255);"><span class="" style="font-size: 11px;"> [<span class="" style="color: rgb(209, 47, 27);">"1"</span>,<span class="Apple-converted-space"> </span><span class="" style="color: rgb(209, 47, 27);">"2"</span>,<span class="Apple-converted-space"> </span><span class="" style="color: rgb(209, 47, 27);">"apple"</span>,<span class="Apple-converted-space"> </span><span class="" style="color: rgb(209, 47, 27);">"banana"</span>,<span class="Apple-converted-space"> </span><span class="" style="color: rgb(209, 47, 27);">"5"</span>].<span class="" style="color: rgb(49, 89, 93);">selectiveMap</span>({ (x)-><span class="" style="color: rgb(79, 129, 135);">SelectiveMapResult</span><<span class="" style="color: rgb(112, 61, 170);">Int</span>><span class="Apple-converted-space"> </span><span class="" style="color: rgb(186, 45, 162);">in</span></span></div></div><div class=""><div class="" style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo; background-color: rgb(255, 255, 255);"><span class="" style="font-size: 11px;"> <span class="Apple-converted-space"> </span><span class="" style="color: rgb(186, 45, 162);">if</span><span class="Apple-converted-space"> </span><span class="" style="color: rgb(186, 45, 162);">let</span><span class="Apple-converted-space"> </span>value =<span class="Apple-converted-space"> </span><span class="" style="color: rgb(112, 61, 170);">Int</span>(x) {<span class="Apple-converted-space"> </span><span class="" style="color: rgb(186, 45, 162);">return</span><span class="Apple-converted-space"> </span>.<span class="" style="color: rgb(49, 89, 93);">use</span>(value) }</span></div></div><div class=""><div class="" style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo; background-color: rgb(255, 255, 255);"><span class="" style="font-size: 11px;"> <span class="Apple-converted-space"> </span><span class="" style="color: rgb(186, 45, 162);">else</span><span class="Apple-converted-space"> </span>{<span class="Apple-converted-space"> </span><span class="" style="color: rgb(186, 45, 162);">return</span><span class="Apple-converted-space"> </span>.<span class="" style="color: rgb(49, 89, 93);">ignore</span><span class="Apple-converted-space"> </span>}</span></div></div><div class=""><div class="" style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo; background-color: rgb(255, 255, 255);"><span class="" style="font-size: 11px;"> })</span></div></div><div class="" style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo; background-color: rgb(255, 255, 255);"><span class="" style="font-size: 11px;"><br class=""></span></div><div class="" style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo; background-color: rgb(255, 255, 255);"><span class="" style="font-size: 11px;">actualNumbers == [1, 2, 5]</span></div></blockquote><div class="" style="margin: 0px; font-stretch: normal; font-size: 11px; line-height: normal; font-family: Menlo; background-color: rgb(255, 255, 255);"><br class=""></div><div class="" style="margin: 0px; font-stretch: normal; line-height: normal; background-color: rgb(255, 255, 255);">The “selective” part of this operation doesn’t feel like it’s changing the type of the result, because<span class="Apple-converted-space"> </span><font face="Menlo" class="">SelectiveMapResult</font><span class="Apple-converted-space"> </span>is easily understood to not be part of the mapping transformation; it just exists to tell us whether we should<span class="Apple-converted-space"> </span><i class="">use the result</i><span class="Apple-converted-space"> </span>of that particular transformation. Likewise, I don’t feel like the optional in<span class="Apple-converted-space"> </span><font face="Menlo" class="">filterMap</font><span class="Apple-converted-space"> </span>is part of the mapping operation; it’s just serving the same role as<span class="Apple-converted-space"> </span><font face="Menlo" class="">SelectiveMapResult</font>. (It should be obvious that<span class="Apple-converted-space"> </span><font face="Menlo" class="">SelectiveMapResult</font><span class="Apple-converted-space"> </span>is just<span class="Apple-converted-space"> </span><font face="Menlo" class="">Optional</font><span class="Apple-converted-space"> </span>with another name here.)</div></div></div></blockquote><div class=""><br class=""></div><div class="">"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. </div><div class=""><br class=""></div><div class="">"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". </div><div class=""><br class=""></div><div class="">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 }".</div><div class=""><br class=""></div><div class=""><br class=""></div><blockquote type="cite" class=""><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space;"><div class="" style="margin: 0px; font-stretch: normal; line-height: normal; background-color: rgb(255, 255, 255);">The name<span class="Apple-converted-space"> </span><font face="Menlo" class="">filterMap</font><span class="Apple-converted-space"> </span>focuses on removing the ignored values, as does<span class="Apple-converted-space"> </span><font face="Menlo" class="">compactMap</font>. The name<span class="Apple-converted-space"> </span><font face="Menlo" class="">selectiveMap</font><span class="Apple-converted-space"> </span>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<span class="Apple-converted-space"> </span><font face="Menlo" class="">compactMap</font>, 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<span class="Apple-converted-space"> </span><font face="Menlo" class="">Sequence.compact()</font><span class="Apple-converted-space"> </span>alongside<span class="Apple-converted-space"> </span><font face="Menlo" class="">.compactMap()</font>, I’d probably get used to it.</div></div></div></blockquote><br class=""></div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;">Swift doesn't use "filter" to mean "drop the nil values" either. </div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><br class=""></div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><br class=""></div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;">"compactMap" is okay if "compact" is added. Is "compact" a common enough operation in practice to pull its own weight?</div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><br class=""></div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;">"mapSome" is great if you know about Optional.Some but terrible if you don't. ("Okay, it maps some elements, but which ones?") </div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><br class=""></div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;">"mapNonNil" is obvious and ugly and perhaps its obviousness makes it a winner.</div></div></blockquote><div class=""><br class=""></div></div><div class="">mapSome and especially mapNonNil both sound to me like they only map the non-nil values in the source sequence.</div></div></div></blockquote><br class=""></div><div class="">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.</div></div></div></blockquote><div class=""><br class=""></div>func filterMap<T>(_ f: (Element) -> T?) -> [T] {</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""> return self.map(f).filter { $0 != nil }.map( $0! } // not an efficient implementation</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">}<br class=""><div class=""><br class=""></div>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.</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br class=""></div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">John.</div><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">_______________________________________________</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">swift-evolution mailing list</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><a href="mailto:swift-evolution@swift.org" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;" class="">swift-evolution@swift.org</a><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a></div></blockquote></div><br class=""></div></body></html>