<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body><div>I use that flatMap() variant on sequences very often. I don't think I've actually _ever_ used the variant that returns [T]. I understand the monadic argument you're making, but I believe the practical choice here is to keep this flatMap() variant as-is. Giving it a different name would I think reduce clarity, since it's conceptually performing the same operation (e.g. the closure returns some value that is flattened; whether the values an array or an optional it doesn't matter), and adding .filterNils() would not only reduce clarity but would, as you said, have a performance impact.<br></div>
<div> </div>
<div>Personally, I'd be in favor of making Optional conform to SequenceType. I've filed a radar on it before, and I seem to recall a message (probably to this list) yesterday suggesting the exact same thing. It may even want to go ahead and adopt CollectionType too, completely replacing CollectionOfOne (though the ability to subscript an optional may be confusing, so it may be better to just adopt SequenceType and keep CollectionOfOne around for CollectionType use-cases).<br></div>
<div> </div>
<div>-Kevin Ballard</div>
<div> </div>
<div>On Fri, Dec 4, 2015, at 03:26 PM, Andy Matuschak wrote:<br></div>
<blockquote type="cite"><div>Hello, all! This SequenceType-implemented flatMap recently caused some confusion on my team:<br></div>
<div> </div>
<blockquote style="margin-top:0px;margin-right:0px;margin-bottom:0px;margin-left:40px;border-top-style:none;border-right-style:none;border-bottom-style:none;border-left-style:none;border-top-width:initial;border-right-width:initial;border-bottom-width:initial;border-left-width:initial;border-top-color:initial;border-right-color:initial;border-bottom-color:initial;border-left-color:initial;border-image-source:initial;border-image-slice:initial;border-image-width:initial;border-image-outset:initial;border-image-repeat:initial;padding-top:0px;padding-right:0px;padding-bottom:0px;padding-left:0px;"><div><span class="font" style="font-family:Menlo">func flatMap<T>(@noescape transform: (Self.Generator.Element) throws -> T?) rethrows -> [T]</span><br></div>
</blockquote><div> </div>
<div>I’m a big fan of this operator in various functional libraries, but I admit I was a bit surprised to see the “flatMap” terminology appear in the Swift stdlib in the first place—its naming is certainly a notch obscure!<br></div>
<div> </div>
<div>From the reactions of teammates in code reviews involving these methods, there was a significant difference in comprehensibility between the <span class="font" style="font-family:Menlo">Element -> [T]</span> variant and the <span class="font" style="font-family:Menlo">Element -> T?</span> variant. The former was easily explained by “it’s a map, followed by a flatten,” whereas the same explanation failed in the latter case.<br></div>
<div> </div>
<div>I expect that the inspiration came from Scala, where the equivalent definition has a transformer essentially of type <span class="font" style="font-family:Menlo">Element -> GeneratorType<T></span>; separately, their optionals are implicitly convertible to (their equivalent of) <span class="font" style="font-family:Menlo">GeneratorType</span>. So, in the end, in Scala, you can effectively flatMap with an <span class="font" style="font-family:Menlo">Element -> T?</span> transformer.<br></div>
<div> </div>
<div>But <span class="font" style="font-family:Menlo">Optional</span> doesn’t implement <span class="font" style="font-family:Menlo">GeneratorType</span>, and I’d (weakly) argue that it shouldn’t. And if we think about <span class="font" style="font-family:Menlo">flatMap</span> in the context of a monadic bind (I do, anyway!), it’s especially surprising that the transformer is operating in a different monadic context (<span class="font" style="font-family:Menlo">Optional</span>) than the receiver (<span class="font" style="font-family:Menlo">SequenceType</span>). Unless we made <span class="font" style="font-family:Menlo">Optional</span> adopt <span class="font" style="font-family:Menlo">SequenceType</span>, in which case we could consider the bind to be happening in that context.<br></div>
<div> </div>
<div>In conclusion, I argue that this overload is confusing both to folks unfamiliar with FP (because it doesn’t feel like Optionals can be flattened) and to folks familiar with FP (because it implies binding across monadic contexts).<br></div>
<div> </div>
<div>~<br></div>
<div> </div>
<div>In terms of what to do instead: I do think that this is a useful method, and I’d like to keep this functionality easily accessible! Two ideas:<br></div>
<div> </div>
<div>1. We expose a separate operator like:<br></div>
<div> </div>
<blockquote style="margin-top:0px;margin-right:0px;margin-bottom:0px;margin-left:40px;border-top-style:none;border-right-style:none;border-bottom-style:none;border-left-style:none;border-top-width:initial;border-right-width:initial;border-bottom-width:initial;border-left-width:initial;border-top-color:initial;border-right-color:initial;border-bottom-color:initial;border-left-color:initial;border-image-source:initial;border-image-slice:initial;border-image-width:initial;border-image-outset:initial;border-image-repeat:initial;padding-top:0px;padding-right:0px;padding-bottom:0px;padding-left:0px;"><div><span class="font" style="font-family:Menlo">extension SequenceType where Generator.Element: OptionalType {</span><br></div>
<div><span class="font" style="font-family:Menlo"><span style="white-space:pre;"></span>func filterNils() -> [Generator.Element.Wrapped]</span><br></div>
<div><span class="font" style="font-family:Menlo">}</span><br></div>
<div> </div>
<div><span class="font" style="font-family:Menlo">// To deal with limitations on protocol extension type restriction:</span><br></div>
<div><span class="font" style="font-family:Menlo">protocol OptionalType {</span><br></div>
<div><span class="font" style="font-family:Menlo"><span style="white-space:pre;"></span>typealias Wrapped</span><br></div>
<div><span class="font" style="font-family:Menlo"><span style="white-space:pre;"></span>func flatMap<Result>(@noescape f: Wrapped -> Result?) -> Result?</span><br></div>
<div><span class="font" style="font-family:Menlo">}</span><br></div>
<div><span class="font" style="font-family:Menlo">extension Optional: OptionalType {}</span><br></div>
<div> </div>
</blockquote><div>Clients would do <span class="font" style="font-family:Menlo">myArray.map(optionalReturningTransform).filterNils()</span>. There would be some performance impact from the intermediate array.<br></div>
<div> </div>
<div>2. We give the foo variant a more specific name, e.g. <span class="font" style="font-family:Menlo">mappedArrayFilteringNils</span> etc. Naming this is tricky (which probably implies it should be decomposed?).
<img style="height:1px !important;width:1px !important;border-top-width:0px !important;border-right-width:0px !important;border-bottom-width:0px !important;border-left-width:0px !important;margin-top:0px !important;margin-bottom:0px !important;margin-right:0px !important;margin-left:0px !important;padding-top:0px !important;padding-bottom:0px !important;padding-right:0px !important;padding-left:0px !important;" border="0" height="1" width="1" alt="" src="https://www.fastmailusercontent.com/proxy/d1ffb81dba5b328a11c5489c9cf7966dbc63c34c560234d34ef03995d03b705f/8647470737a3f2f25723030323431303e23647e23756e64676279646e2e65647f27766f2f60756e6f35707e6d3148765176786c673171614a7d2236454230345272776e475576363b6674566d22364d65757c465d223647774837313030597a777a51483b654e4769654567475d22364a7e655968757b465c40586f443e49775437375859575e656c407c4f6c484b414a565f6a6b674348564842584654774a69505e416649574e645547473b443836717e4738607d22364234395158366474593e463e6a717e617e645c496748797d6d627e6953505653596e63414c61735e68605650784c426d22364743376555703d64454a6031674c663d2236457168705037383a4374397837667e4537636734315d23344d23344/open"><br></div>
<div><u>_______________________________________________</u><br></div>
<div>swift-evolution mailing list<br></div>
<div><a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a><br></div>
<div><a href="https://lists.swift.org/mailman/listinfo/swift-evolution">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br></div>
</blockquote><div> </div>
</body>
</html>