Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
// Define the following traits and companion object
// It's in Rapture Core (https://github.com/propensive/rapture-core) if you don't want to
trait LowPriorityDefaultsTo { implicit def fallback[T, S]: DefaultsTo[T, S] = null }
object DefaultsTo extends LowPriorityDefaultsTo { implicit def defaultDefaultsTo[T]: DefaultsTo[T, T] = null }
trait DefaultsTo[T, S]
// Then, assuming we want to specify a default for a type class like `Namer`,
case class Namer[T](name: String)
// where we have a couple of alternatives,
implicit val stringNamer = Namer[String]("string")
implicit val intNamer = Namer[Int]("int")
// we define the default one for a particular method like this:
def myMethod[T](implicit default: T DefaultsTo String, namer: Namer[T]) = namer.name
// Let's try it out in the REPL:
scala> myMethod
res0: String = string
scala> myMethod[Int]
res1: String = int
@sourcedelica

This comment has been minimized.

Copy link

@sourcedelica sourcedelica commented Feb 2, 2015

Very nice. I just added this to a much-used utility we have and it worked like a charm. Thanks!

@propensive

This comment has been minimized.

Copy link
Owner Author

@propensive propensive commented Feb 11, 2015

Cool! :)

@chirlo

This comment has been minimized.

Copy link

@chirlo chirlo commented May 8, 2015

It's even more expectacular if you change it to case class Namer[T](t:T) , then you get type safety on the default value!

@4lex1v

This comment has been minimized.

Copy link

@4lex1v 4lex1v commented Oct 12, 2015

Jon, i wonder why did you place fallback to LowPriorityDefaultsTo, if i understand SLS correctly there's no ambiguity between these two implicits, since defaultDefaultsTo more specific then fallback, so if we omit the type parameter, the compiler would pick it instead of fallback, hence no ambiguity. So why placing it on a different layer?

To be sure this compiles on 2.11.7

trait DefaultsTo[Type, Default]
object DefaultsTo {
  implicit def fallback[T, D]: DefaultsTo[T, D] = null
  implicit def defaultDefaultsTo[T]: DefaultsTo[T, T] = null
}

trait Document
final class Table[DocType](val name: String)(implicit default: DocType DefaultsTo Document)

object Test {
  val table = new Table("settings")
  val table2 = new Table[String]("settings2")
}
@propensive

This comment has been minimized.

Copy link
Owner Author

@propensive propensive commented Oct 15, 2015

@4lex1v If that works, great! I tend to ignore the type-specificity rules and go straight with stacked traits, but that's a useful optimization!

@yanns

This comment has been minimized.

Copy link

@yanns yanns commented Oct 15, 2015

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment