Evidence that type T has annotation A, and provides an instance of the annotation.
Provides the annotations of type A of the fields or constructors of case class-like or sum type T.
Provides the annotations of type A of the fields or constructors of case class-like or sum type T.
If type T is case class-like, this type class inspects its fields and provides their annotations of type A. If
type T is a sum type, its constructor types are looked for annotations.
Type Out is an HList having the same number of elements as T (number of fields of T if T is case class-like,
or number of constructors of T if it is a sum type). It is made of None.type (no annotation on corresponding
field or constructor) and Some[A] (corresponding field or constructor is annotated).
Method apply provides an HList of type Out made of None (corresponding field or constructor not annotated)
or Some(annotation) (corresponding field or constructor has annotation annotation).
Note that annotation types must be case class-like for this type class to take them into account.
Example:
case class First(s: String) case class CC(i: Int, @First("a") s: String) sealed trait Base @First("b") case class BaseI(i: Int) extends Base case class BaseS(s: String) extends Base val ccFirsts = Annotations[First, CC] val baseFirsts = Annotations[First, Base] // ccFirsts.Out is None.type :: Some[First] :: HNil // ccFirsts.apply() is // None :: Some(First("a")) :: HNil // baseFirsts.Out is Some[First] :: None.type :: HNil // baseFirsts.apply() is // Some(First("b")) :: None :: HNil
Wraps a cached implicit T.
Wraps a cached implicit T.
Looking for an implicit Cached[T] first triggers a look for an implicit T, caches the resulting
tree, and returns it immediately and in subsequent look ups for an implicit Cached[T]. Thus,
subsequent look ups do not trigger looking for an implicit T, only returning the instance kept in
cache.
Beware that if the contexts in which two subsequent look ups are different, so that looking for a
T in each of them doesn't return the same result, this change would be ignored by caching. Looking
for a Cached[T] in the first context would put the implicit T of this context in cache, and then
looking for a Cached[T] in the second context would return the former instance from the first
context. E.g.
trait TC[T] { def msg: String } object First { implicit val tc: TC[Int] = new TC[Int] { val msg = "first" } def print() = println(implicitly[TC[Int]].msg) def printCached() = println(cached[TC[Int]].msg) } object Second { implicit val tc: TC[Int] = new TC[Int] { val msg = "second" } def print() = println(implicitly[TC[Int]].msg) def printCached() = println(cached[TC[Int]].msg) } First.print() Second.print() First.printCached() Second.printCached()
would print "first" then "second" (non cached TC[Int] instances), then "first" twice (first instance, returned
the second time too through the cache).
Provides default values of case class-like types.
Provides default values of case class-like types.
The Out type parameter is an HList type whose length is the number of fields of T. Its elements correspond
to the fields of T, in their original order. It is made of None.type (no default value for this field) and
Some[...] (default value available for this field, with ... the type of the field). Note that None.type and
Some[...] are more precise than simply Option[...], so that the availability of default values can be used
in type level calculations.
The apply method returns an HList of type Out, with None elements corresponding to no default value available,
and Some(defaultValue) to default value available for the corresponding fields.
Use like
case class CC(i: Int, s: String = "b") val default = Default[CC] // default.Out is None.type :: Some[String] :: HNil // default() returns // None :: Some("b") :: HNil, // typed as default.Out
Allows to ignore some implicits in a LowPriority[T].
Allows to ignore some implicits in a LowPriority[T].
Use like .T, T]]LowPriority[Ignoring[Witness."ignoredMethod".
Typical usage is when a fallback for type class TC is defined in its companion, like
object TC { implicit def anyTC[T]: TC[T] = ... }
With the example of LowPriority[T] above,
trait TC[T] { def prop: Option[Boolean] } trait LowPriTC { // default low priority TC[T] for any T, with field `prop` equal to `None` implicit def anyTC[T]: TC[T] = new TC[T] { def prop = None } } object TC extends LowPriTC { // TC[Int] available by default, with field `prop` equal to `Some(true)` implicit val intTC: TC[Int] = new TC[Int] { def prop = Some(true) } } // extra `TC[T]`, with field `prop` equal to `Some(false)` implicit def extraTC[T](implicit ev: LowPriority[Ignoring[Witness.`"anyTC"`.T, TC[T]]]): TC[T] = new TC[T] { def prop = Some(false) } // Already available instance `intTC` is still found, because `extraTC[Int]` requires a // `LowPriority[TC[Int]]`, that will refuse to materialize (because `LowPriority` is able to // know about the already available `intTC`.) assert(implicitly[TC[Int]].prop == true) // `extraTC[String]` is found, as the default `anyTC[String]` is ignored, assert(implicitly[TC[String]].prop == false)
Wraps a lazily computed value.
Wraps a lazily computed value. Also circumvents cycles during implicit search, or wrong implicit divergences as illustrated below, and holds the corresponding implicit value lazily.
The following implicit search sometimes fails to compile, because of a wrongly reported implicit divergence,
case class ListCC(list: List[CC]) case class CC(i: Int, s: String) trait TC[T] object TC { implicit def intTC: TC[Int] = ??? implicit def stringTC: TC[String] = ??? implicit def listTC[T](implicit underlying: TC[T]): TC[List[T]] = ??? implicit def genericTC[F, G](implicit gen: Generic.Aux[F, G], underlying: TC[G] ): TC[F] = ??? implicit def hnilTC: TC[HNil] = ??? implicit def hconsTC[H, T <: HList](implicit headTC: TC[H], tailTC: TC[T] ): TC[H :: T] = ??? } implicitly[TC[CC]] // fails with: diverging implicit expansion for type TC[CC]
This wrongly reported implicit divergence can be circumvented by wrapping some of the implicit values in
Lazy,
case class ListCC(list: List[CC]) case class CC(i: Int, s: String) trait TC[T] object TC { implicit def listTC[T](implicit underlying: TC[T]): TC[List[T]] = ??? implicit def genericTC[F, G](implicit gen: Generic.Aux[F, G], underlying: Lazy[TC[G]] // wrapped in Lazy ): TC[F] = ??? implicit def hnilTC: TC[HNil] = ??? implicit def hconsTC[H, T <: HList](implicit headTC: Lazy[TC[H]], // wrapped in Lazy tailTC: TC[T] ): TC[H :: T] = ??? } implicitly[TC[CC]]
When looking for an implicit Lazy[TC[T]], the Lazy.mkLazy macro will itself trigger the implicit search
for a TC[T]. If this search itself triggers searches for types wrapped in Lazy, these will be done
only once, their result put in a lazy val, and a reference to this lazy val will be returned as the corresponding
value. It will then wrap all the resulting values together, and return a reference to the first one.
E.g. with the above example definitions, when looking up for an implicit TC[CC], the returned tree roughly looks
like
TC.genericTC( Generic[CC], // actually, the tree returned by Generic.materialize, not written here for the sake of brevity Lazy { lazy val impl1: TC[List[CC] :: HNil] = TC.hconsTC( Lazy(impl2), TC.hnilTC ) lazy val impl2: TC[List[CC]] = TC.listTC(TC.genericTC( Generic[CC], // actually, the tree returned by Generic.materialize Lazy(impl1) // cycles to the initial TC[List[CC] :: HNil] )) impl1 } )
Lazy extension companions should extend this trait, and return a new LazyExtension instance via
instantiate.
Lazy extension companions should extend this trait, and return a new LazyExtension instance via
instantiate.
These companions typically provide a materializer method like
implicit def init[H]: Wrapper[T] = macro initImpl
,
where Wrapper is the wrapper type that this extension handles, and initImpl is provided by
the LazyExtensionCompanion trait. This initializes the extension upon first use during
a Lazy / Strict implicit search.
Evidence that no implicit T instance is available elsewhere.
Evidence that no implicit T instance is available elsewhere.
The instance using the LowPriority[T] is ignored.
Allows to prioritize implicits, for example
trait TC[T] { def prop: Boolean } object TC { // TC[Int] available by default, with field `prop` true implicit val intTC: TC[Int] = new TC[Int] { def prop = true } } // extra `TC[T]`, with field `prop` false implicit def extraTC[T](implicit ev: LowPriority[TC[T]]): TC[T] = new TC[T] { def prop = false } // Already available instance `intTC` is still found, because `extraTC[Int]` requires a // `LowPriority[TC[Int]]`, that will refuse to materialize (because `LowPriority` is able to // know about the already available `intTC`.) assert(implicitly[TC[Int]].prop == true) // `extraTC[String]` is found, as no other `TC[String]` can be found elsewhere assert(implicitly[TC[String]].prop == false)
Wraps an eagerly computed value.
Wraps an eagerly computed value. Prevents wrongly reported implicit divergence, like Lazy does, but,
unlike it, does not circumvent implicit cycles.
Creation of Lazy instances usually triggers the creation of an anonymous class, to compute the wrapped
value (e.g. with the by-name argument of Lazy.apply). Strict avoids that, which can lead to less
overhead during compilation.
A utility which ensures that a code fragment does not typecheck.
A utility which ensures that a code fragment does not typecheck.
Credit: Stefan Zeiger (@StefanZeiger)
Evidence that type
Thas annotationA, and provides an instance of the annotation.If type
Thas an annotation of typeA, then an implicitAnnotation[A, T]can be found, and itsapplymethod provides an instance of the annotation.Example: