Currently configurable type class derivation can be achieved by requiring extra implicit arguments to the derived
method. Example (from Circe Derivation PR):
object ConfiguredEncoder:
def derived[A](using c: Configuration)(using m: Mirror.Of[A]): ConfiguredEncoder[A] = ???
Usage:
- Using a global configuration for every derivation:
// Somewhere in the global implicit scope
given Configuration = Configuration.default.withSnakeCaseNames
case class Foo(s: String = "bar", i: Int) derives ConfiguredEncoder
- Using a specific configuration (this also overrides any configuration that might exist in the global scope):
object Bar:
given Configuration = Configuration.default.withDiscriminator("_type")
case class Foo(s: String = "bar", i: Int) derives ConfiguredEncoder
This could be improved in the following ways:
- The
derives
syntax could behave likewith
, that is, this would be valid:
case class Foo(s: String = "bar", i: Int)
derives ConfiguredEncoder
derives ConfiguredDecoder
derives Eq
derives Show
Just like with the extends either all type class derivations must use the derives
keyword or all must use the comma separated list (eg: derives ConfiguredEncoder, ConfiguredDecoder, Eq, Show
)
- When, and only when, using the above syntax this would be valid:
case class Foo(s: String = "bar", i: Int)
derives ConfiguredEncoder(using Configuration.default.withDiscriminator("_type"))
Making it succinct and to the point. Even more so if multiple val
s with distinct configurations are declared globally. For example:
case class Foo(s: String = "bar", i: Int)
derives ConfiguredEncoder(using discriminatorConf)
- The derives method could accept non implicit arguments:
object ConfiguredEncoder:
def derived[A](
transformMemberNames: String => String = identity,
transformConstructorNames: String => String = identity,
useDefaults: Boolean = true,
discriminator: Option[String] = None,
strictDecoding: Boolean = false,
)(using m: Mirror.Of[A]): ConfiguredEncoder[A] = ???
If all non-implicit arguments define default values then the comma separated list syntax can be used. Otherwise the derives
keyword per derivation must be used passing in the intended values. This would allow usages like:
case class Foo(s: String = "bar", i: Int)
derives ConfiguredEncoder(useDefaults = false, discriminator = Some("is_a"))