Skip to content

Commit e18d8b0

Browse files
author
Dave Abrahams
committed
[stdlib] filter(x) never creates a Collection
It's both more rigorously correct and should prevent surprise when constructing an Array from a filtered sequence. See the comments in-code for details. Swift SVN r19304
1 parent a4db36b commit e18d8b0

File tree

2 files changed

+27
-4
lines changed

2 files changed

+27
-4
lines changed

stdlib/core/Filter.swift

+25-2
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,29 @@
6868
return lhs._pos == rhs._pos
6969
}
7070

71-
/// The lazy `Collection` returned by `filter(c)` where `c` is a
72-
/// `Collection`
71+
/// A lazy `Collection` wrapper that includes the elements of an
72+
/// underlying collection that satisfy a predicate. Not
73+
/// automatically returned by `filter(x)` for two reasons:
74+
///
75+
/// * The O(1) guarantee of our `IndexType` would be iffy at best, since
76+
/// it advances an underlying `Index` until the predicate is
77+
/// satisfied. Be aware that a `FilterCollectionView` may not offer
78+
/// the expected efficiency for this reason.
79+
///
80+
/// * Constructing an `Array` from a `Collection` measures the length
81+
/// of the collection before traversing it to read the elements.
82+
/// This causes the filter predicate to be called twice for each
83+
/// element of the underlying collection, which is surprising.
7384
@public struct FilterCollectionView<Base: Collection> : Collection {
7485

7586
@public typealias IndexType = FilterCollectionViewIndex<Base>
87+
88+
@public
89+
init(_ base: Base, includeElement: (Base.GeneratorType.Element)->Bool) {
90+
self._base = base
91+
self._include = includeElement
92+
}
93+
7694
@public var startIndex: IndexType {
7795
var first = _base.startIndex
7896
while first != _base.endIndex {
@@ -111,10 +129,15 @@
111129
return FilterSequenceView(_base: source, _include: includeElement)
112130
}
113131

132+
/*
133+
// No overload for collections; see the comment on
134+
// FilterCollectionView for an explanation.
135+
114136
/// Return a lazy Collection containing the elements `x` of `source` for
115137
/// which `includeElement(x)` is `true`
116138
@public func filter<C:Collection>(
117139
source: C, includeElement: (C.GeneratorType.Element)->Bool
118140
) -> FilterCollectionView<C> {
119141
return FilterCollectionView(_base: source, _include: includeElement)
120142
}
143+
*/

test/stdlib/Filter.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ func printlnByIndexing<C: Collection>(c: C) {
3232

3333
// Test filtering Collections
3434
if true {
35-
let f0 = filter(0..<30) { $0 % 7 == 0 }
35+
let f0 = FilterCollectionView(0..<30) { $0 % 7 == 0 }
3636

3737
// CHECK-NEXT: <0, 7, 14, 21, 28>
3838
printlnByGenerating(f0)
@@ -41,7 +41,7 @@ if true {
4141

4242
// Also try when the first element of the underlying sequence
4343
// doesn't pass the filter
44-
let f1 = filter(1..<30) { $0 % 7 == 0 }
44+
let f1 = FilterCollectionView(1..<30) { $0 % 7 == 0 }
4545

4646
// CHECK-NEXT: <7, 14, 21, 28>
4747
printlnByGenerating(f1)

0 commit comments

Comments
 (0)