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

more in-depth README #62

Merged
merged 5 commits into from
Dec 16, 2015
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 69 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,80 @@

This is a Swift µframework providing `Result<Value, Error>`.

`Result<Value, Error>` values are either successful (wrapping `Value`) or failed (wrapping `Error`). This is similar to Swift’s native `Optional` type, with the addition of an error value to pass some error code, message, or object along to be logged or displayed to the user.
`Result<Value, Error>` values are either successful (wrapping `Value`) or failed (wrapping `Error`). This is similar to Swift’s native `Optional` type: `Success` is like `Some`, and `Failure` is like `None` except with an associated `ErrorType` value. The addition of an associated `ErrorType` allows errors to be passed along for logging or displaying to the user.

Using this µframework instead of rolling your own `Result` type allows you to easily interface with other frameworks that also use `Result`.

## Use

[API documentation](http://cocoadocs.org/docsets/Result/) is in the source.
Use `Result` whenever an operation has the possibility of failure. Consider the following example of a function that tries to extract a `String` for a given key from a JSON `Dictionary`.

```swift
typealias JSONObject = [String:AnyObject]

enum JSONError : ErrorType {
case NoSuchKey(String)
case TypeMismatch
}

func stringForKey(json: JSONObject, key: String) -> Result<String, JSONError> {
guard let value = json[key] else {
return .Failure(.NoSuchKey(key))
}

if let value = value as? String {
return .Success(value)
}
else {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's more common to put these on single line like } else {

return .Failure(.TypeMismatch)
}
}
```

This function provides a more robust wrapper around the default subscripting provided by `Dictionary`. Rather than return `AnyObject?`, it returns a `Result` that either contains the `String` value for the given key, or an `ErrorType` detailing what went wrong.

One simple way to handle a `Result` is to deconstruct it using a `switch` statement.

```swift
switch stringForKey(json, key: "email") {

case let .Success(email):
print("The email is \(email)")

case let .Failure(JSONError.NoSuchKey(key)):
print("\(key) is not a valid key")

case .Failure(JSONError.TypeMismatch):
print("Didn't have the right type")
}
```

Using a `switch` statement allows powerful pattern matching, and ensures all possible results are covered. Swift 2.0 offers new ways to deconstruct enums like the `if-case` statement, but be wary as such methods do not ensure errors are handled.

Other methods available for processing `Result` are detailed in the [API documentation](http://cocoadocs.org/docsets/Result/).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The link to cocoadocs.org is a great idea, thank you.


## Result vs. Throws
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be worth also mentioning that you can't use throws with asynchronous APIs.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that it'd be helpful to have more information here and possibly an example.


Swift 2.0 introduces error handling via throwing and catching `ErrorType`. `Result` accomplishes the same goal by encapsulating the result instead of hijacking control flow. The `Result` abstraction allows enables powerful functionality such as `map` and `flatMap`, making `Result` more composable than `throw`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

abstraction allows enables powerful


Since dealing with APIs that throw is common, you can convert functions such functions into a `Result` by using the `materialize` method. Conversely, a `Result` can be used to throw an error by calling `dematerialize`. [Note: due to compiler issues, `materialize` is not currently available]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can convert functions such functions into

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It'd be great to see an example here and a note about what compiler issues are preventing this from moving forward.


## Higher Order Functions

`map` and `flatMap` operate the same as `Optional.map` and `Optional.flatMap` except they apply to `Result`.

`map` transforms a `Result` into a `Result` of a new type. It does this by taking a function that transforms the `Value` type into a new value. This transformation is only applied in the case of a `Success`. In the case of a `Failure`, the associated error is re-wrapped in the new `Result`.

```swift
// transforms a Result<Int, JSONError> to a Result<String, JSONError>
let idResult = intForKey(json, key:"id").map { id in String(id) }
```

Here, the final result is either the id as a `String`, or carries over the `.Failure` from the previous result.

`flatMap` is similar to `map` in that in transforms the `Result` into another `Result`. However, the function passed into `flatMap` must return a `Result`.

An in depth discussion of `map` and `flatMap` is beyond the scope of this documentation. If you would like a deeper understanding, read about functors and monads. This article is a good place to [start](http://www.javiersoto.me/post/106875422394).

## Integration

Expand Down