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-3166] Sequence.first(where:) shouldn't use throw internally for success #45754

Open
swift-ci opened this issue Nov 9, 2016 · 9 comments
Open

Comments

@swift-ci
Copy link
Collaborator

swift-ci commented Nov 9, 2016

Previous ID SR-3166
Radar None
Original Reporter fpillet (JIRA User)
Type Improvement
Additional Detail from JIRA
Votes 1
Component/s Source Tooling, Standard Library
Labels Improvement
Assignee None
Priority Medium

md5: 542fdb4ae8d528fadb931fcece9b2e86

Issue Description:

The implementation for the new `Sequence.first(where:)` function in Swift 3 internally uses a `throw _StopIteratop.stop` to exit a `forEach` loop on success.

While merits of this approach can be discussed, the immediate impact on developers is that Xcode breaks every time an item is found when using the Break on Swift Errors debugger breakpoint.

Since Xcode internally breaks on `swift_willThrow()` when you ask it to break on Swift Errors, the standard library should refrain from internally using `throw` for regular control flow until tooling can support filtering of false positives.

One way or the other, the current state of things should change. One solution would be that swiftc does not emit the call to `swift_willThrow()` in certain known internal cases.

@swift-ci
Copy link
Collaborator Author

swift-ci commented Nov 9, 2016

Comment by Florent Pillet (JIRA)

Link to the relevant piece of code in standard library: Sequence.first implementation

@swift-ci
Copy link
Collaborator Author

swift-ci commented Nov 18, 2016

Comment by Russ Bishop (JIRA)

IIRC I did it this way to avoid allocating an iterator for types where that is expensive; the type itself may have a more optimal implementation of forEach since it can guarantee nothing escapes... the throwing is just a way to jump out of the forEach and has minimal overhead.

Can you explain why you think this should be changed?

@swift-ci
Copy link
Collaborator Author

swift-ci commented Nov 18, 2016

Comment by Russ Bishop (JIRA)

My originally implementation used a for loop; I'm not opposed to changing it back. The original change was at @gribozavr's request IIRC so you might ask him

@swift-ci
Copy link
Collaborator Author

swift-ci commented Nov 18, 2016

Comment by Florent Pillet (JIRA)

Hi Russ thanks for your answer.

When you run your application with Xcode, you have the option to set it to break on `throw` so as to be able to catch throws early in your code, and examine what's wrong.

Since you are using `throw` for a case that is not an error, I get a break in debugger every time I use `first` and it is successful.

This is highly inconvenient when you use `first` a lot and you get Xcode debugger pausing your app for nothing. In my case I had to rewrite a `first` implementation that doesn't use `throw` because I use this function a lot.

@natecook1000
Copy link
Member

natecook1000 commented Dec 6, 2016

I have a fix for this issue at the link below, but there's some question about whether this is best handled in the stdlib or should be addressed in Xcode. (I don't think we want to adopt a "no throwing in stdlib code" policy.) I also haven't been able to reproduce this behavior in my latest version of Xcode, so it may be a moot point.
#5867

I'm going to close the PR for now—fpillet (JIRA User), can you check if you're still able to reproduce this in the latest Xcode?

@tonyarnold
Copy link
Contributor

tonyarnold commented Jan 11, 2017

@natecook1000 just confirming that I'm still seeing this (really annoying) behaviour in the latest public release of Xcode (8.2.1).

I don't think "no throwing in stdlib" is at issue - what I'm reading is that there's some contention about using throw for non-error related purposes.

How would Xcode differentiate between a "good" throw that's not an error, and a real throw? I guess it's up to the two teams to coordinate as to the correct place to fix this issue, but this is impacting my use of Swift/Xcode now.

@hamishknight
Copy link
Collaborator

hamishknight commented Apr 1, 2017

I feel it's worth noting that performance can be a concern here, although only for a large number (in the order of millions) of repeated applications of first(where:) (one example of this bottleneck was encountered here: http://codereview.stackexchange.com/q/158798/104723). Although I'm unsure of whether this is a good justification for changing the implementation back to using a for-in loop, given the potential benefits from allowing custom sequences to provide a custom forEach(_:) implementation.

@nicklockwood
Copy link
Contributor

nicklockwood commented Jun 15, 2018

What about introducing a standard flow control Error type that bypasses the swift_willThrow() breakpoint? I have historically implemented similar "no-error" errors myself (and then refactored to remove them due to the debugging issue), so maybe this is a useful pattern that is worth supporting?

@martinr448
Copy link

martinr448 commented Feb 27, 2020

As far as I can see, `first(where:)` does not throw an error for flow control anymore, so this can be closed?

8b9dd25

@swift-ci swift-ci transferred this issue from apple/swift-issues Apr 25, 2022
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

6 participants