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

Add arrow.generic.Coproduct docs #998

Merged
merged 10 commits into from
Sep 1, 2018

Conversation

abergfeld
Copy link
Contributor

This adds docs for Coproducts. I largely based this off the Products docs that already existed. I'm not sure if I have to add anything else to get these setup with the web pages or how all that works. These are my first Arrow docs so feedback would be much appreciated :)

@JorgeCastilloPrz
Copy link
Member

If you wanna test the docs locally:

Run Ank, it'll deploy docs locally for you.
./gradlew :arrow-docs:runAnk in the root Arrow folder.

Once that's finished, go to modules/docs/arrow-docs/ and then

jekyll serve --source build/site/

That will launch the site on 127.0.0.1:4000. You'll need Jekyll installed.

@abergfeld
Copy link
Contributor Author

@JorgeCastilloPrz Thanks! I got the readme code compiling and hooked up the menu and it's all working locally 🎉

@codecov
Copy link

codecov bot commented Aug 27, 2018

Codecov Report

Merging #998 into master will not change coverage.
The diff coverage is n/a.

Impacted file tree graph

@@            Coverage Diff            @@
##             master     #998   +/-   ##
=========================================
  Coverage     47.04%   47.04%           
  Complexity      694      694           
=========================================
  Files           320      320           
  Lines          8090     8090           
  Branches        848      848           
=========================================
  Hits           3806     3806           
  Misses         3941     3941           
  Partials        343      343

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update ab442f2...ed00f01. Read the comment docs.


Coproducts represent a container in which only one of the specified set of types exist. It's very similar in `Either` in that respect. `Either` supports one of two values, an `Either<A, B>` has to contain an instance of `A` or `B`. We can extrapolate that concept to `N` number of types. So a `Coproduct5<A, B, C, D, E>` has to contain an instance of `A`, `B`, `C`, `D`, or `E`. For example, perhaps there's a search function for a Car Dealer app that can show `Dealership`s, `Car`s and `SalesPerson`s, we could model that list of results as `List<Coproduct3<Dealership, Car, SalesPerson>`. The result would contain a list of heterogeneous elements but each element is one of `Dealership`, `Car` or `SalesPerson` and our UI can render the list elements based on those types.

Let's say we have an api. Our api operates under the following conditions:
Copy link
Member

Choose a reason for hiding this comment

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

All this scenarios would work better using very simple code snippets.


#### Coproduct

Coproducts represent a container in which only one of the specified set of types exist. It's very similar in `Either` in that respect. `Either` supports one of two values, an `Either<A, B>` has to contain an instance of `A` or `B`. We can extrapolate that concept to `N` number of types. So a `Coproduct5<A, B, C, D, E>` has to contain an instance of `A`, `B`, `C`, `D`, or `E`. For example, perhaps there's a search function for a Car Dealer app that can show `Dealership`s, `Car`s and `SalesPerson`s, we could model that list of results as `List<Coproduct3<Dealership, Car, SalesPerson>`. The result would contain a list of heterogeneous elements but each element is one of `Dealership`, `Car` or `SalesPerson` and our UI can render the list elements based on those types.
Copy link
Member

Choose a reason for hiding this comment

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

Please add links to Either docs everytime you mention it.

val apiResult = coproductOf<CommonServerError, RegistrationError, Registration>(ServerError) //Returns Coproduct3<CommonServerError, RegistrationError, Registration>
```

There are `coproductOf` constructor functions for each Coproduct. All we have to do is pass in our value and have the correct type parameters on it, the value must be a type declared on the function call.
Copy link
Member

Choose a reason for hiding this comment

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

First line, I'd better say "...for each Coproduct regardless of the arity (number of types)."

{:.beginner}
beginner

`arrow-generic` provides meta programming facilities over Product types like data classes, tuples, and heterogeneous lists; and Coproduct types like sealed classes.
Copy link
Member

Choose a reason for hiding this comment

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

What about "arrow-generic provides meta programming facilities over Product types (data classes, tuples, heterogeneous lists...). It also provides the Coproduct type, similar to sealed classes.

(Even if by implementation we're providing N Coproduct types, semantically all of them are the same thing, the Coproduct, I don't think there's need here to state it's a bunch of them, at least not yet on this paragraph)


#### Coproduct

Coproducts represent a container in which only one of the specified set of types exist. It's very similar in `Either` in that respect. `Either` supports one of two values, an `Either<A, B>` has to contain an instance of `A` or `B`. We can extrapolate that concept to `N` number of types. So a `Coproduct5<A, B, C, D, E>` has to contain an instance of `A`, `B`, `C`, `D`, or `E`. For example, perhaps there's a search function for a Car Dealer app that can show `Dealership`s, `Car`s and `SalesPerson`s, we could model that list of results as `List<Coproduct3<Dealership, Car, SalesPerson>`. The result would contain a list of heterogeneous elements but each element is one of `Dealership`, `Car` or `SalesPerson` and our UI can render the list elements based on those types.
Copy link
Member

@JorgeCastilloPrz JorgeCastilloPrz Aug 28, 2018

Choose a reason for hiding this comment

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

"Coproducts represent a sealed hierarchy of types where only one of the specified set of types exist every time. Conceptually, it's very similar to the stdlib sealed class, or to Either if we move on to Arrow data types."

Copy link
Member

Choose a reason for hiding this comment

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

"...Car Dealer app that can show Dealerships, Cars and SalesPersons on a list.."

All we have to do is provide the type parameters and we can make a Coproduct using the `cop` extension method. Just like `coproductOf`, if the type of the value isn't in the type parameters of the method call, it won't compile:

```kotlin:ank
//val apiResult = ServerError.cop<String, RegistrationError, Registration>()
Copy link
Member

Choose a reason for hiding this comment

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

Can we write the exception thrown here?


##### fold

Obviously, we're not just modeling errors for fun, we're going to handle them! All Coproducts have `fold` which allows us to condense the Coproduct down to a single type. For example, we could handle errors as such in a UI:
Copy link
Member

@JorgeCastilloPrz JorgeCastilloPrz Aug 28, 2018

Choose a reason for hiding this comment

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

Maybe we can add some note here about exhaustive evaluation?

)
```

Here we're able to return the result of the `fold` and we're forced to handle all cases! Neat!
Copy link
Member

Choose a reason for hiding this comment

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

Ah! There it is. Maybe just explicitly mention exhaustive evaluation here. You're saying it but still mentioning it by its real name should help.


##### select

Let's say we also want to store the `Registration` object into our database when we successfully register a car. We don't really want to have to `fold` over every single case just to handle something for the `Registration`, this is where `select<T>` comes to the rescue! We're able to take a Coproduct and `select` the type we care about from it. `select` returns an `Option`, if the value of the Coproduct was for the type you're trying to `select`, you'll get `Some`, if it was not the type used with `select`, you'll get `None`.
Copy link
Member

@JorgeCastilloPrz JorgeCastilloPrz Aug 28, 2018

Choose a reason for hiding this comment

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

Maybe we could move all the first part until "...select comes to the rescue!" to the previous section. Then you present select as a new section, which would start as "We're able to take a...". That helps to start introducing the concept by the need for it before even giving it a name. It's just a more gradual way to put it.

@abergfeld
Copy link
Contributor Author

@JorgeCastilloPrz I updated the docs, I think I addressed everything. Let me know if there's anything else :)

@abergfeld
Copy link
Contributor Author

@ffgiraldez Would you be able to help me figure out what's happening with the code coverage testing here, it all looks like stuff that hasn't changed as part of this PR.


fun handleApiResult(apiResult: Coproduct3<CommonServerError, RegistrationError, Registration>): Unit {
// apiResult.select<String>()
//error: type mismatch: inferred type is Coproduct3<CommonServerError, RegistrationError, Registration> but Coproduct3<String, *, *> was expected
Copy link
Member

Choose a reason for hiding this comment

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

This reminds me that Ank should have a mode for expecting and printing errors similar to how we do now ank:silent. but ank:error so users are not forced to comment out code that fails to compile and can let the compiler provide the actual error that gets rendered along the snippet.

Copy link
Member

Choose a reason for hiding this comment

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

@ffgiraldez
Copy link
Member

I will check It tomorrow

@raulraja
Copy link
Member

raulraja commented Sep 1, 2018

thanks @abergfeld !

@raulraja raulraja merged commit b5ec6e4 into arrow-kt:master Sep 1, 2018
@calvellido calvellido added docs and removed docs labels Oct 17, 2018
@raulraja raulraja mentioned this pull request Nov 2, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants