<div dir="ltr"><div class="gmail_default" style="font-family:georgia,serif">What about dropping T, just using Element, and converting Element to the type in your predicate?</div><div class="gmail_default" style="font-family:georgia,serif"><br></div><div class="gmail_default" style="font-family:georgia,serif">zhaoxin</div></div><div class="gmail_extra"><br><div class="gmail_quote">On Wed, Jan 20, 2016 at 6:09 PM, Marco Masser via swift-users <span dir="ltr">&lt;<a href="mailto:swift-users@swift.org" target="_blank">swift-users@swift.org</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word">I want to write an extension on <span style="color:rgb(112,61,170);font-family:Menlo;font-size:11px">SequenceType</span> that contains a set of methods named <span style="font-family:Menlo;font-size:11px">findFirst()</span> that should return the first element that matches the given predicate.<div><br></div><div>For heterogeneous sequences where the caller is only interested in a specific subtype of elements, it is useful to have a variant of <span style="font-family:Menlo;font-size:11px">findFirst()</span> that allows somehow specifying the type the caller is interested in so the predicate closure only gets called with that specific type.</div><div><br></div><div>That was probably not very easy to understand, but this example hopefully explains it clearly:</div><div>In an <span style="color:rgb(112,61,170);font-family:Menlo;font-size:11px">NSView</span>’s <span style="color:rgb(112,61,170);font-family:Menlo;font-size:11px">subviews</span> array (which are <span style="color:rgb(112,61,170);font-family:Menlo;font-size:11px">NSView</span>s), find the first <span style="color:rgb(112,61,170);font-family:Menlo;font-size:11px">NSButton</span> whose <span style="color:rgb(112,61,170);font-family:Menlo;font-size:11px">state</span> is <span style="color:rgb(112,61,170);font-family:Menlo;font-size:11px">NSOnState</span>. It would be neat if the predicate closure that checks the <span style="color:rgb(112,61,170);font-family:Menlo;font-size:11px">state</span> property only gets passed <span style="color:rgb(112,61,170);font-family:Menlo;font-size:11px">NSButton</span>s and no <span style="color:rgb(112,61,170);font-family:Menlo;font-size:11px">NSView</span>s because that eliminates type checks in the closure.</div><div><br></div><div>I have two candidates for the implementation of this method and I’m looking for the more idiomatic one.</div><div><br></div><div>The examples work with a variable called <span style="color:rgb(79,129,135);font-family:Menlo;font-size:11px">containerView</span>, which is of type <span style="color:rgb(112,61,170);font-family:Menlo;font-size:11px">NSView</span>.</div><div><br></div><div>First try:</div><div><br></div><div><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(112,61,170)"><span style="color:#bb2ca2">extension</span><span style="color:#000000"> </span>SequenceType<span style="color:#000000"> {</span></div><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;min-height:13px"><br></div><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;min-height:13px"><span style="color:rgb(187,44,162)">    @warn_unused_result</span></div><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">    <span style="color:#bb2ca2">func</span> findFirst&lt;T&gt;(<span style="color:#bb2ca2">_</span>: T.Type, <span style="color:#bb2ca2">@noescape</span> matching predicate: T <span style="color:#bb2ca2">throws</span> -&gt; <span style="color:#703daa">Bool</span>) <span style="color:#bb2ca2">rethrows</span> -&gt; <span style="color:#703daa">T</span>? {</div><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">        <span style="color:#bb2ca2">for</span> <span style="color:#bb2ca2">case</span> <span style="color:#bb2ca2">let</span> element <span style="color:#bb2ca2">as</span> <span style="color:#703daa">T</span> <span style="color:#bb2ca2">in</span> <span style="color:#bb2ca2">self</span> <span style="color:#bb2ca2">where</span> <span style="color:#bb2ca2">try</span> predicate(element) {</div><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">            <span style="color:#bb2ca2">return</span> element</div><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">        }</div><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">        <span style="color:#bb2ca2">return</span> <span style="color:#bb2ca2">nil</span></div><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">    }</div><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;min-height:13px"><br></div><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">}</div><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;min-height:13px"><br></div><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo"><span style="color:#bb2ca2">let</span> result1 = <span style="color:#4f8187">containerView</span>.<span style="color:#703daa">subviews</span>.<span style="color:#31595d">findFirst</span>(<span style="color:#703daa">NSButton</span>.<span style="color:#bb2ca2">self</span>, matching: { $0.<span style="color:#703daa">state</span> == <span style="color:#703daa">NSOnState</span> })</div></div><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo"><br></div><div style="margin:0px;line-height:normal">Here, the first parameter (which is ignored in the implementation) pins down the type of the generic parameter. Note that the predicate’s parameter is of type <span style="color:rgb(112,61,170);font-family:Menlo;font-size:11px">NSButton</span> so there’s no <span style="color:rgb(187,44,162);font-family:Menlo;font-size:11px">as</span><span style="font-family:Menlo;font-size:11px">?</span> or something like that necessary.</div><div style="margin:0px;line-height:normal"><br></div><div style="margin:0px;line-height:normal">But there’s another way to pin down the generic parameter:</div><div style="margin:0px;line-height:normal"><br></div><div style="margin:0px;line-height:normal"><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(112,61,170)"><span style="color:#bb2ca2">extension</span><span style="color:#000000"> </span>SequenceType<span style="color:#000000"> {</span></div><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;min-height:13px"><br></div><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;min-height:13px"><div style="margin:0px;line-height:normal;color:rgb(187,44,162)">    @warn_unused_result</div></div><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">    <span style="color:#bb2ca2">func</span> findFirst&lt;T&gt;(<span style="color:#bb2ca2">@noescape</span> matching predicate: T <span style="color:#bb2ca2">throws</span> -&gt; <span style="color:#703daa">Bool</span>) <span style="color:#bb2ca2">rethrows</span> -&gt; <span style="color:#703daa">T</span>? {</div><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">        <span style="color:#bb2ca2">for</span> <span style="color:#bb2ca2">case</span> <span style="color:#bb2ca2">let</span> element <span style="color:#bb2ca2">as</span> <span style="color:#703daa">T</span> <span style="color:#bb2ca2">in</span> <span style="color:#bb2ca2">self</span> <span style="color:#bb2ca2">where</span> <span style="color:#bb2ca2">try</span> predicate(element) {</div><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">            <span style="color:#bb2ca2">return</span> element</div><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">        }</div><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">        <span style="color:#bb2ca2">return</span> <span style="color:#bb2ca2">nil</span></div><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">    }</div><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;min-height:13px"><br></div><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">}</div></div><div style="margin:0px;line-height:normal"><br></div><div style="margin:0px;line-height:normal"><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(112,61,170)"><span style="color:#bb2ca2">let</span><span style="color:#000000"> result2: </span>NSButton<span style="color:#000000">? = </span><span style="color:#4f8187">containerView</span><span style="color:#000000">.</span>subviews<span style="color:#000000">.</span><span style="color:#31595d">findFirst</span><span style="color:#000000"> { $0.</span>state<span style="color:#000000"> == </span>NSOnState<span style="color:#000000"> }</span></div></div><div style="margin:0px;line-height:normal"><br></div><div style="margin:0px;line-height:normal">This time, the generic parameter is inferred at call site by explicitly specifying the type of the <span style="font-family:Menlo;font-size:11px">result2</span> variable.</div><div style="margin:0px;line-height:normal"><br></div><div style="margin:0px;line-height:normal">Note that with this implementation of <span style="font-family:Menlo;font-size:11px">findFirst()</span> it’s also possible to pin down the generic parameter by giving the closure parameter a specific type:</div><div style="margin:0px;line-height:normal"><br></div><div style="margin:0px;line-height:normal"><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo"><span style="color:#bb2ca2">let</span> result3 = <span style="color:#4f8187">containerView</span>.<span style="color:#703daa">subviews</span>.<span style="color:#31595d">findFirst</span> { (button: <span style="color:#703daa">NSButton</span>) <span style="color:#bb2ca2">in</span> button.<span style="color:#703daa">state</span> == <span style="color:#703daa">NSOnState</span> }</div></div><div style="margin:0px;line-height:normal"><br></div><div style="margin:0px;line-height:normal"><br></div><div style="margin:0px;line-height:normal">The first implementation seems nice to me at the call site because users of the API can’t miss specifying the type of <span style="color:rgb(112,61,170);font-family:Menlo;font-size:11px">T</span>. But I don’t really like the way <span style="font-family:Menlo;font-size:11px;color:rgb(112,61,170)">NSButton</span><span style="font-family:Menlo;font-size:11px">.</span><span style="font-family:Menlo;font-size:11px;color:rgb(187,44,162)">self</span> looks and from a language standpoint, the first parameter is redundant. It’s even ignored in the implementation!</div><div style="margin:0px;line-height:normal"><br></div><div style="margin:0px;line-height:normal">The second implementation seems more correct to me, but at the call site, it may be easy to miss specifying the resulting variable’s type, which leads to a compiler error that is not 100% obvious to newcomers (“Type of expression is ambiguous without more context” pointing at the <span style="font-family:Menlo;font-size:11px">$0</span>), which leads to users thinking about what they did wrong, which leads to them coming to me asking how to use this method.</div><div style="margin:0px;line-height:normal"><br></div><div style="margin:0px;line-height:normal"><br></div><div style="margin:0px;line-height:normal">I’d love to hear comments on this and what you think is the better way to implement this. If that were a method in the Swift Standard Library, how would you expect it to work?</div><div style="margin:0px;line-height:normal"><br></div><div style="margin:0px;line-height:normal">(Bonus question: Why isn’t there a method like this in the Standard Library?)</div></div><br>_______________________________________________<br>
swift-users mailing list<br>
<a href="mailto:swift-users@swift.org">swift-users@swift.org</a><br>
<a href="https://lists.swift.org/mailman/listinfo/swift-users" rel="noreferrer" target="_blank">https://lists.swift.org/mailman/listinfo/swift-users</a><br>
<br></blockquote></div><br></div>