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

Update guidelines.md with implicit priority #2095

Merged
merged 1 commit into from
Dec 12, 2017
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
29 changes: 28 additions & 1 deletion docs/src/main/tut/guidelines.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ The user doesn't need to specify the type `A` which is given by the parameter.
You probably noticed that there is a `val dummy: Boolean` in the `PurePartiallyApplied` class. This is a trick we used
to make this intermediate class a [Value Class](http://docs.scala-lang.org/overviews/core/value-classes.html) so that there is no cost of allocation, i.e. at runtime, it doesn't create an instance of `PurePartiallyApplied`. We also hide this partially applied class by making it package private and placing it inside an object.

### <a id="ops-classes" href="#implicit-naming"></a> Implicit naming
### <a id="implicit-naming" href="#implicit-naming"></a> Implicit naming

In a widely-used library it's important to minimize the chance that the names of implicits will be used by others and
therefore name our implicits according to the following rules:
Expand All @@ -84,5 +84,32 @@ As an example, an implicit instance of `Monoid` for `List` defined in the packag

This rule is relatively flexible. Use what you see appropriate. The goal is to maintain uniqueness and avoid conflicts.



### <a id="implicit-priority" href="#implicit-priority"></a> Implicit instance priority

When there are multiple instances provided implicitly, if the type class of them are in the same inheritance hierarchy,
the instances need to be separated out into different abstract class/traits so that they don't conflict with each other. The names of these abstract classes/traits should be numbered with a priority with 0 being the highest priority. The abstract classes/trait
with higher priority inherits from the ones with lower priority. The most specific (whose type class is the lowest in the hierarchy) instance should be placed in the abstract class/ trait with the highest priority. Here is an example.

```scala
@typeclass
trait Functor[F[_]]

@typeclass
trait Monad[F[_]] extends Functor

...
object Kleisli extends KleisliInstance0

abstract class KleisliInstance0 extends KleisliInstance1 {
implicit def catsDataMonadForKleisli[F[_], A]: Monad[Kleisli[F, A, ?]] = ...
}

abstract class KleisliInstance1 {
implicit def catsDataFunctorForKleisli[F[_], A]: Functor[Kleisli[F, A, ?]] = ...
Copy link
Contributor

Choose a reason for hiding this comment

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

It's really outside of the point of this example, but my mental compiler complained that you would need F[_]:Monad and F[_]:Functor constraints to be able to implement them :)

}
```

#### TODO:
Once we drop 2.10 support, AnyVal-extending class constructor parameters can be marked as private.