-
Notifications
You must be signed in to change notification settings - Fork 431
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
Rename SignalProducer.Type.attempt
to init(_:)
.
#346
Conversation
Does this ambiguity cause problems in practice? It's ambiguous for our test suite because we do this: let operation: () -> Result<String, NSError> = {
operationRunTimes += 1
return .success("OperationValue")
}
SignalProducer.attempt(operation).start()
SignalProducer.attempt(operation).start() But I think that's understandable. Ordinarily, you wouldn't use a This is okay, for instance: let operation: () -> Result<String, NSError> = {
operationRunTimes += 1
return .success("OperationValue")
}
func makeProducer() -> SignalProducer<String, NSError> {
return .attempt(operation)
}
makeProducer().start()
makeProducer().start() |
The type checker works in this context: func attempt(_ operation: @escaping () -> Result<String, NSError>) -> SignalProducer<(), NSError> {
return SignalProducer.attempt(operation)
.on(started: { started += 1 })
.map { _ in }
} But not if the func attempt2(_ operation: @escaping () -> Result<String, AnyError>) -> SignalProducer<(), AnyError> {
return SignalProducer.attempt(operation) // Ambiguous use of `attempt`.
.on(started: { started += 1 })
.map { _ in () }
} |
I think we could add a 3rd overload to disambiguate that. extension SignalProducerProtocol where Error == AnyError {
public static func attempt(_ operation: @escaping () -> Result<Value, Error>) -> SignalProducer<Value, Error>
} That seems like the same thing we do for |
The problem is that the type checker can infer |
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.
Just want to give my 👍 purely from an API design point of view here. An initialiser strikes me as more idiomatic in Swift.
As a side note (mentioned on Slack), there is a workaround for public protocol _AnyError {}
extension AnyError: _AnyError {}
extension SignalProducer where Value: _AnyError { ... } |
/// - operation: A failable closure. | ||
public init(_ action: @escaping () throws -> Value) { | ||
self.init { | ||
return ReactiveSwift.materialize { |
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.
I don't think we actually need this materialize
alias. I think we can do Result(attempt: try action())
.
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.
I still prefer .attempt
, but I accept that Swift has tied our hands here.
a9f6538
to
3dc5f34
Compare
I've just experienced a weirdness due to this and the |
FYI I suffered this again in Carthage: Carthage/Carthage#2077. |
Follow-up to #304.
The original signatures are ambiguous, but they somehow work as protocol extensions in Swift 3. Moving them to the concrete type reveals the ambiguity.
Consider
.attempt { () -> Result<Int, NoError> in .success(1) }
, the closure can satisfy both methods and produce:SignalProducer<Int, NoError>
; orSignalProducer<Result<Int, NoError>, AnyError>
since non-throwing closures are covariant of their throwing version.Solution
Renaming
SignalProducer.Type.attempt
toinit(_:)
mitigated the ambiguity. How this happens is uncertain, given that Swift has no documentation on the overload selection rules at the moment.Edit: It is suspected that these as static functions require the compiler to consider two additional generic parameters in the return type. Being
init(_:)
, however, binds the return type to beSelf
, and reduce the overload selection factors to the arguments.