Skip to content
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

[SR-11841] Lazy filter runs in unexpected order #54246

Closed
swift-ci opened this issue Nov 24, 2019 · 6 comments
Closed

[SR-11841] Lazy filter runs in unexpected order #54246

swift-ci opened this issue Nov 24, 2019 · 6 comments

Comments

@swift-ci
Copy link
Collaborator

swift-ci commented Nov 24, 2019

Previous ID SR-11841
Radar rdar://problem/57549147
Original Reporter dtorres (JIRA User)
Type Bug
Status Resolved
Resolution Done
Environment

Xcode 11.2.1

Additional Detail from JIRA
Votes 0
Component/s Standard Library
Labels Bug
Assignee None
Priority Medium

md5: 281a0f54ddfb46f82336abd5abaa9562

Issue Description:

For the following code:

var array = ["1", "2", "3"]


let filtered = array.lazy
    .filter({ _ in
        print("A")
        return true
    }).filter { _ in
        print("B")
        return true
}

_ = Array(filtered)

Actual Results:

B
A
B
A
B
A

Expected Results:

A
B
A
B
A
B

I would expect a cascade behaviour of A filtering before B*. However, this prints:

*Not to confuse with non lazy behaviour of AAABBB which is indeed correct

@swift-ci
Copy link
Collaborator Author

swift-ci commented Nov 24, 2019

Comment by Diego Torres (JIRA)

It is indeed wrong.
https://github.com/apple/swift/blob/master/stdlib/public/core/Filter.swift#L341

Thanks @natecook1000

@swift-ci
Copy link
Collaborator Author

swift-ci commented Nov 24, 2019

Comment by Diego Torres (JIRA)

And a PR to fix it #28462

@pcantrell
Copy link

pcantrell commented Nov 24, 2019

An interesting example that came up discussing this bug, just to demonstrate how insidious it can be:

var valuesEncountered = Set<String>()

var result = ["bangle", "bannister", "banjo"]
    .filter({ valuesEncountered.insert($0).inserted })
    .filter({ valuesEncountered.insert(String($0.prefix(3))).inserted })

print(valuesEncountered)  // ["bangle", "bannister", "banjo", "ban”]

…as expected. But make it lazy, which should give the same results:

var valuesEncountered = Set<String>()

var result = ["bangle", "bannister", "banjo"]
    .lazy  // go lazy
    .filter({ valuesEncountered.insert($0).inserted })
    .filter({ valuesEncountered.insert(String($0.prefix(3))).inserted })

Array(result)  // force evaluation
print(valuesEncountered)  // ["ban", "bangle”] ← oops!

But then if we trigger lazy evaluation with a contextual type instead of an explicit Array(…) call:

var valuesEncountered = Set<String>()

// Now [String] type forces evaluation instead
var result: [String] = ["bangle", "bannister", "banjo"]
    .lazy  // go lazy
    .filter({ valuesEncountered.insert($0).inserted })
    .filter({ valuesEncountered.insert(String($0.prefix(3))).inserted })

print(valuesEncountered)  // ["bangle", "ban", "banjo", "bannister”]

@beccadax
Copy link
Contributor

beccadax commented Dec 2, 2019

@swift-ci create

@natecook1000
Copy link
Member

natecook1000 commented Dec 2, 2019

Just as a note, that last example isn't using lazy evaluation — providing the type of the result as [String] selects the filter method from the Sequence protocol rather than the one implemented directly on the LazySequence type.

@natecook1000
Copy link
Member

natecook1000 commented Dec 4, 2019

Fixed in #28462

@swift-ci swift-ci transferred this issue from apple/swift-issues Apr 25, 2022
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants