Skip to content

Instantly share code, notes, and snippets.

@danslapman
Last active January 24, 2020 14:12
Show Gist options
  • Select an option

  • Save danslapman/f9a46aaac90db8d8ac9ae3f34188255a to your computer and use it in GitHub Desktop.

Select an option

Save danslapman/f9a46aaac90db8d8ac9ae3f34188255a to your computer and use it in GitHub Desktop.
Quirky patterns
//https://github.com/mongodb/mongo-scala-driver/blob/master/bson/src/main/scala/org/mongodb/scala/bson/DefaultHelper.scala
/**
* Neat helper to obtain a default type should one not be given eg:
*
* {{{
* def find[T]()(implicit e: T DefaultsTo Document) { ... }
* }}}
*
* The signature of the `find` method ensures that it can only be called if the caller can supply an object of type
* `DefaultsTo[T, Document]`. Of course, the [[DefaultsTo.default]] and `[[DefaultsTo.overrideDefault]] methods make it easy to create
* such an object for any type `T`. Since these methods are implicit, the compiler automatically handles the business of calling one of
* them and passing the result into `find`.
*
* ''But how does the compiler know which method to call?'' It uses its type inference and implicit resolution rules to determine the
* appropriate method. There are three cases to consider:
*
* 1. `find` is called with no type parameter. In this case, type T must be inferred. Searching for an implicit method that can provide
* an object of type `DefaultsTo[T, Document]`, the compiler finds `default` and `overrideDefault`. `default` is chosen since it has
* priority (because it's defined in a proper subclass of the trait that defines overrideDefault). As a result, T must be bound to
* `Document.
*
* 2. `find` is called with a non-Document type parameter (e.g., `find[BsonDocument]()`). In this case, an object of type
* `DefaultsTo[BsonDocument, Document]` must be supplied. Only the `overrideDefault` method can supply it, so the compiler inserts the
* appropriate call.
*
* 3. `find` is called with `Document` as the type parameter. Again, either method is applicable, but default wins due to its higher
* priority.
*
*/
sealed class DefaultsTo[A, B]
/**
* Companion object for [[DefaultsTo]]
*/
object DefaultsTo extends LowPriorityDefaultsTo {
/**
* Implicitly sets a default type of B. See [[DefaultsTo]]
*
* @tparam B the default type
* @return Defaults[B, B] instance
*/
implicit def default[B]: DefaultsTo[B, B] = new DefaultsTo[B, B]
}
/**
* Lower priority defaultsTo implicit helper
*/
trait LowPriorityDefaultsTo {
/**
* Overrides the default with the set type of A. See [[DefaultsTo]]
*
* @tparam A The type to use
* @tparam B The default type incase type A was missing
* @return Defaults[A, B] instance
*/
implicit def overrideDefault[A, B]: DefaultsTo[A, B] = new DefaultsTo[A, B]
}
//https://github.com/monix/monix/blob/master/monix-catnap/shared/src/main/scala/monix/catnap/OrElse.scala
/** A type class for prioritized implicit search.
*
* Useful for specifying type class instance alternatives.
* Examples:
*
* - `Async[F] OrElse Sync[F]`
* - `Concurrent[F] OrElse Async[F]`
*
* Inspired by the implementations in Shapeless and Algebra.
*/
sealed trait OrElse[+A, +B] {
def fold[C](prim: A => C, sec: B => C): C
def unify[C >: B](implicit ev: A <:< C): C
}
object OrElse extends OrElse0 {
implicit def primary[A, B](implicit a: A): A OrElse B =
new Primary(a)
}
private[catnap] abstract class OrElse0 {
implicit def secondary[A, B](implicit b: B): A OrElse B =
new Secondary(b)
final class Primary[+A](value: A) extends OrElse[A, Nothing] {
def fold[C](prim: A => C, sec: Nothing => C) = prim(value)
def unify[C >: Nothing](implicit ev: <:<[A, C]): C = value
}
final class Secondary[+B](value: B) extends OrElse[Nothing, B] {
def fold[C](prim: Nothing => C, sec: B => C) = sec(value)
def unify[C >: B](implicit ev: <:<[Nothing, C]): C = value
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment