[swift-users] Which is the more idiomatic approach for pinning down the type of a generic parameter?

zhaoxin肇鑫 owenzx at gmail.com
Wed Jan 20 04:25:53 CST 2016


What about dropping T, just using Element, and converting Element to the
type in your predicate?

zhaoxin

On Wed, Jan 20, 2016 at 6:09 PM, Marco Masser via swift-users <
swift-users at swift.org> wrote:

> I want to write an extension on SequenceType that contains a set of
> methods named findFirst() that should return the first element that
> matches the given predicate.
>
> For heterogeneous sequences where the caller is only interested in a
> specific subtype of elements, it is useful to have a variant of
> findFirst() that allows somehow specifying the type the caller is
> interested in so the predicate closure only gets called with that specific
> type.
>
> That was probably not very easy to understand, but this example hopefully
> explains it clearly:
> In an NSView’s subviews array (which are NSViews), find the first NSButton
>  whose state is NSOnState. It would be neat if the predicate closure that
> checks the state property only gets passed NSButtons and no NSViews
> because that eliminates type checks in the closure.
>
> I have two candidates for the implementation of this method and I’m
> looking for the more idiomatic one.
>
> The examples work with a variable called containerView, which is of type
> NSView.
>
> First try:
>
> extension SequenceType {
>
>     @warn_unused_result
>     func findFirst<T>(_: T.Type, @noescape matching predicate: T throws
> -> Bool) rethrows -> T? {
>         for case let element as T in self where try predicate(element) {
>             return element
>         }
>         return nil
>     }
>
> }
>
> let result1 = containerView.subviews.findFirst(NSButton.self, matching: {
> $0.state == NSOnState })
>
> 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 NSButton so there’s no as? or something like that necessary.
>
> But there’s another way to pin down the generic parameter:
>
> extension SequenceType {
>
>     @warn_unused_result
>     func findFirst<T>(@noescape matching predicate: T throws -> Bool)
> rethrows -> T? {
>         for case let element as T in self where try predicate(element) {
>             return element
>         }
>         return nil
>     }
>
> }
>
> let result2: NSButton? = containerView.subviews.findFirst { $0.state ==
> NSOnState }
>
> This time, the generic parameter is inferred at call site by explicitly
> specifying the type of the result2 variable.
>
> Note that with this implementation of findFirst() it’s also possible to
> pin down the generic parameter by giving the closure parameter a specific
> type:
>
> let result3 = containerView.subviews.findFirst { (button: NSButton) in
> button.state == NSOnState }
>
>
> The first implementation seems nice to me at the call site because users
> of the API can’t miss specifying the type of T. But I don’t really like
> the way NSButton.self looks and from a language standpoint, the first
> parameter is redundant. It’s even ignored in the implementation!
>
> 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 $0), which
> leads to users thinking about what they did wrong, which leads to them
> coming to me asking how to use this method.
>
>
> 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?
>
> (Bonus question: Why isn’t there a method like this in the Standard
> Library?)
>
> _______________________________________________
> swift-users mailing list
> swift-users at swift.org
> https://lists.swift.org/mailman/listinfo/swift-users
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-users/attachments/20160120/bacff639/attachment.html>


More information about the swift-users mailing list