Comments (6)
Why are you using WrapperError
instead of AnyError
?
I'm curious why you'd do this and what benefit you're getting from it.
from result.
So, WrapperError
is just an example of a concrete struct or enum that conforms to Error
and can be initialized with an arbitrary Error
(just like AnyError
).
Let's say I have an error like this:
enum StringMangleError : Swift.Error, ErrorInitializing {
case emptyString
case stringTooLong
case other(Error)
init(_ error: Swift.Error) {
if let stringMangleError = error as? StringMangleError {
self = stringMangleError
} else {
self = .somethingOtherHappened(error)
}
}
}
And I have a function that throws:
func mangle(_ string: String) throws -> String {
guard !string.isEmpty else { throw StringMangleError.stringEmpty }
guard string.count < 256 else { throw StringMangleError.stringTooLong }
let mangledString = //... do some mangling
return mangledString
}
Now let's say I want to do the mangling asynchronously. The only way I can think of writing that function now would be:
func asyncMangle(_ string: String, completion: (Result<String, StringMangleError>) -> Void) {
do {
completion(.success(try mangle(string)))
} catch {
completion(.failure(StringMangleError(error)))
}
}
But with the proposed changes, it would be as easy as:
func asyncMangle(_ string: String, completion: (Result<String, StringMangleError>) -> Void) {
completion(Result(attempt: { return try mangle(string) }))
}
from result.
I think the way you'd normally do this with Result would be:
func asyncMangle(_ string: String, completion: (Result<String, StringMangleError>) -> Void) {
let result = Result<String, AnyError>(attempt: { return try mangle(string) })
.mapError { StringMangleError($0.error) }
completion(result)
}
It's not as concise as your example, but I'm not sure the indirection is worth the brevity in this case.
from result.
Right. I guess that's a slightly more brief and functional way of writing that.
However, I wasn't aiming so much for brevity but rather better inference, especially when it comes to errors.
It might seem inconsequential from the provided example but in my current project I'm connecting many classes where each class has its own Error
enum. A less cumbersome way to map
between results where two Result
s have the same associated Value
type but different Error
types would be much appreciated. Better inference for attempt:
initializers (without the need to go through AnyError
) would also greatly reduce clutter in my codebase.
Currently, Result(attempt: {"foo"})
always produces Result<String, AnyError>
, with no possibility to infer other Error
wrappers.
The following will currently not build:
let result: Result<String, CustomError> = Result(attempt: {"foo"} )
To achieve this, one needs to manually map AnyError
to WrapperError
(as you suggested):
let result: Result<String, WrapperError> = Result(attempt: {"foo"} ).mapError{ WrapperError($0.error) }
Additionally, Result({ "foo"})
also currently produces Result<String, AnyError>
, although a non-throwing closure should in my opinion actually produce a Result<String, NoError>
.
There is also currently no default inference for Result(value: "foo")
although the inferred type could easily be Result<String, NoError>
In my updated pull request, the following is true
(assuming BasicError
is just a simple struct that conforms to Error
):
Result({"foo"})
is equivalent toResult<String, NoError>.success("foo")
Result(attempt: {"foo"})
is equivalent toResult<String, AnyError>.success("foo")
Result(attempt: { throw BasicError() }
is equivalent toResult<String, AnyError>.failure(AnyError(BasicError()))
let result: Result<String, WrapperError> = Result(attempt: {"foo"})
is equivalent toResult<String, WrapperError>.success("foo")
and will build ifWrapperError
conforms toErrorInitializing
let result: Result<String, WrapperError> = Result(attempt: { throw BasicError()} )
will build and is equivalent toResult<String, WrapperError>.failure(WrapperError(BasicError()))
ifWrapperError
conforms toErrorInitializing
Result(attempt: { throw WrapperError(BasicError())} )
is equivalent toResult<String, AnyError>.failure(AnyError(BasicError()))
ifWrapperError
conforms toErrorConvertible
(AnyError
will actually wrapWrapperError
's underlyingError
)let basicResult = Result<String, BasicError>(value: "foo")
can be error-mapped withbasicResult.mapError(to: WrapperError.self)
or simplylet wrappedResult: Result<String, WrapperError> = basicResult.mapError()
ifWrapperError
conforms toErrorInitializing
from result.
Here's what I'd suggest:
-
Result(attempt:)
should only be used when calling code you don't control. Anything you do control should return aResult
. You should wrap external code with an interface that returns aResult
. -
The custom errors that your code returns can be mapped into a different
case
s of an outerenum
if you need to handle them in a single spot.
In general, relying on inference isn't a great idea because Swift's type inference is limited. So I'm always hesitant to add an API that relies solely on inference.
from result.
Closing this due to inactivity.
from result.
Related Issues (20)
- Support for higher order functions that can throw HOT 1
- Add Result to swift compatibility check HOT 1
- Replace `NoError` with `Never`? HOT 1
- Lower the `Error: Swift.Error` constraint on `Result` temporarily. HOT 4
- Why not declare 'Result' as 'Result<T>'? So it easy to deal with different types of errors. HOT 6
- [Disabled code coverage for xCode 9] HOT 1
- Unable to use the Result namespace HOT 3
- Non-throwing dematerialize for result using NoError HOT 1
- Change (some) flatMap to compactMap? HOT 2
- 4.0 release HOT 1
- Adding a `fold` method HOT 5
- Result vs. Throws README section is out of date HOT 1
- Result initializer works in for loop but not map? HOT 1
- support required for swift 4.2 HOT 2
- How to pass an array of Swift.Errors as the right (Error) type? HOT 3
- Example os import usage for Swift 5/4 HOT 9
- Migration to Swift 4 HOT 1
- Cocoapods instructions still pin to v4 HOT 3
- Swift 5 support? HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from result.