-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[stdlib] Adding RangeReplaceable.filter returning Self #9741
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
This overload allows `String.filter` to return a `String`, and not `[Character]`. In the other hand, introduction of this overload makes `[123].filter` somewhat ambiguous in a sence, that the compiler will now prefer an implementatin from a more concrete protocol, which is less efficient for arrays, therefore extra work is needed to make sure Array types fallback to the `Sequence.filter`. Implements: <rdar://problem/32209927>
@swift-ci Please test |
@swift-ci Please smoke benchmark |
@swift-ci Please Test Source Compatibility |
public func filter( | ||
_ isIncluded: (Element) throws -> Bool | ||
) rethrows -> Self { | ||
return try Self(self.lazy.filter(isIncluded)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably worth checking that this is just as fast as a hand-rolled loop with append
. It ought to be, and this is definitely the right way to code it, but worth checking. I'll add a benchmark – doesn't need to hold this up though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One cannot regress something that does not exist. 🤷♂️
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here is the snippet I played with:
@inline(never)
public func iteration<
C : RangeReplaceableCollection
>(_ xs: C, _ f: (C.Element) -> Bool) -> C {
var result = C()
var iterator = xs.makeIterator()
while let element = iterator.next() {
if f(element) {
result.append(element)
}
}
return result
}
@inline(never)
public func lazyFilter<
C : RangeReplaceableCollection
>(_ xs: C, _ f: (C.Element) -> Bool) -> C {
return C(xs.lazy.filter(f))
}
for _ in 0..<1_000 {
/*_ = iteration(Array(0..<10000)) { $0 % 2 == 0 }*/
_ = lazyFilter(Array(0..<10000)) { $0 % 2 == 0 }
}
Commenting one and uncommenting the other gives these results on my machine:
# lazyFilter
swiftc -swift-version 3 -O ../filter.swift -o ../filter && time ../filter
../filter 0.59s user 0.00s system 99% cpu 0.604 total
# iteration
swiftc -swift-version 3 -O ../filter.swift -o ../filter && time ../filter
../filter 1.45s user 0.00s system 99% cpu 1.462 total
#lazyFilter
swiftc -swift-version 4 -O ../filter.swift -o ../filter && time ../filter
../filter 0.60s user 0.00s system 99% cpu 0.604 total
# iteration
swiftc -swift-version 4 -O ../filter.swift -o ../filter && time ../filter
../filter 1.46s user 0.00s system 99% cpu 1.469 total
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also both IR and SIL look better in case of lazyFilter
.
@@ -877,6 +877,13 @@ extension Sequence { | |||
public func filter( | |||
_ isIncluded: (Element) throws -> Bool | |||
) rethrows -> [Element] { | |||
return try _filter(isIncluded) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will mean ContiguousArray and ArraySlice will also return an Array from filter, not Self? Which is... probably the right thing? Worth checking my thinking though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's what they have been doing all along. filter
is not redefined anywhere near array types. They all inherit the default Sequence
implementation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, I see what you mean here... The line you commented on is misleading, but yeah, even with the addition of a new overload, they will still return [T]
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right. I was just questioning whether this is the right thing. I think it is for those two types specifically.
Build comment file:Optimized (O) Regression (1)
Improvement (1)
No Changes (270)
Regression (1)
Improvement (2)
No Changes (269)
|
@swift-ci please smoke test linux platform |
This overload allows
String.filter
to return aString
, and not[Character]
.In the other hand, introduction of this overload makes
[123].filter
somewhat ambiguous in a sence, that the compiler will now prefer an
implementatin from a more concrete protocol, which is less efficient for
arrays, therefore extra work is needed to make sure Array types fallback
to the
Sequence.filter
.Implements: rdar://problem/32209927