I have some case classes which have a method tupled defined in its companion object. As it can be seen from the code below in companion objects, it is just code duplication.
case class Book(id: Int, isbn: String, name: String)
object Book {
def tupled = (Book.apply _).tupled // Duplication
}
case class Author(id: Int, name: String)
object Author {
def tupled = (Author.apply _).tupled // Duplication
}
From another question (can a scala self type enforce a case class type), it seems like we can not enforce the self-type of a trait to be a case class.
Is there a way to define a trait (say Tupled) that can be applied as following?
// What would be value of ???
trait Tupled {
self: ??? =>
def tupled = (self.apply _).tupled
}
// Such that I can replace tupled definition with Trait
object Book extends Tupled {
}
Because there's no relationship between FunctionN types in Scala, it's not possible to do this without arity-level boilerplate somewhere—there's just no way to abstract over the companion objects' apply methods without enumerating all the possible numbers of members.
You could do this by hand with a bunch of CompanionN[A, B, C, ...] traits, but that's pretty annoying. Shapeless provides a much better solution, which allows you to write something like the following:
import shapeless.{ Generic, HList }, shapeless.ops.product.ToHList
class CaseClassCompanion[C] {
def tupled[P <: Product, R <: HList](p: P)(implicit
gen: Generic.Aux[C, R],
toR: ToHList.Aux[P, R]
): C = gen.from(toR(p))
}
And then:
case class Book(id: Int, isbn: String, name: String)
object Book extends CaseClassCompanion[Book]
case class Author(id: Int, name: String)
object Author extends CaseClassCompanion[Author]
Which you can use like this:
scala> Book.tupled((0, "some ISBN", "some name"))
res0: Book = Book(0,some ISBN,some name)
scala> Author.tupled((0, "some name"))
res1: Author = Author(0,some name)
You might not even want the CaseClassCompanion part, since it's possible to construct a generic method that converts tuples to case classes (assuming the member types line up):
class PartiallyAppliedProductToCc[C] {
def apply[P <: Product, R <: HList](p: P)(implicit
gen: Generic.Aux[C, R],
toR: ToHList.Aux[P, R]
): C = gen.from(toR(p))
}
def productToCc[C]: PartiallyAppliedProductToCc[C] =
new PartiallyAppliedProductToCc[C]
And then:
scala> productToCc[Book]((0, "some ISBN", "some name"))
res2: Book = Book(0,some ISBN,some name)
scala> productToCc[Author]((0, "some name"))
res3: Author = Author(0,some name)
This will work for case classes with up to 22 members (since the apply method on the companion object can't be eta-expanded to a function if there are more than 22 arguments).
The problem is that the signature of apply differs from case to case, and that there is no common trait for these functions. Book.tupled and Author.tupled basically have the same code, but have very different signatures. Therefore, the solution may not be as nice as we'd like.
I can conceive of a way using an annotation macro to cut out the boilerplate. Since there isn't a nice way to do it with the standard library, I'll resort to code generation (which still has compile-time safety). The caveat here is that annotation macros require the use of the macro paradise compiler plugin. Macros must also be in a separate compilation unit (like another sbt sub-project). Code that uses the annotation would also require the use of the macro paradise plugin.
import scala.annotation.{ StaticAnnotation, compileTimeOnly }
import scala.language.experimental.macros
import scala.reflect.macros.whitebox.Context
#compileTimeOnly("enable macro paradise to expand macro annotations")
class Tupled extends StaticAnnotation {
def macroTransform(annottees: Any*): Any = macro tupledMacroImpl.impl
}
object tupledMacroImpl {
def impl(c: Context)(annottees: c.Expr[Any]*): c.Expr[Any] = {
import c.universe._
val result = annottees map (_.tree) match {
// A case class with companion object, we insert the `tupled` method into the object
// and leave the case class alone.
case (classDef # q"$mods class $tpname[..$tparams] $ctorMods(...$paramss) extends { ..$earlydefns } with ..$parents { $self => ..$stats }")
:: (objDef # q"object $objName extends { ..$objEarlyDefs } with ..$objParents { $objSelf => ..$objDefs }")
:: Nil if mods.hasFlag(Flag.CASE) =>
q"""
$classDef
object $objName extends { ..$objEarlyDefs } with ..$objParents { $objSelf =>
..$objDefs
def tupled = ($objName.apply _).tupled
}
"""
case _ => c.abort(c.enclosingPosition, "Invalid annotation target: must be a companion object of a case class.")
}
c.Expr[Any](result)
}
}
Usage:
#Tupled
case class Author(id: Int, name: String)
object Author
// Exiting paste mode, now interpreting.
defined class Author
defined object Author
scala> Author.tupled
res0: ((Int, String)) => Author = <function1>
Alternatively, something like this may be possible with shapeless. See #TravisBrown's better answer.
Related
Using Scala 2.x macros, how to access literals passed to parent classes when defining subclasses, typically with ADTs such as the following:
sealed abstract class Base(val s: String, val i: Int)
object Base {
case object A extends Base("a", 1)
case object B extends Base("b", 2)
case class C(override val s: String) extends Base(s, 3)
}
For object A, I would like to know parameter values are literals "a" and 1.
For object B, I would like to know parameter values are literals "b" and 2.
For case class C, I would like to know the second parameter is literal 3.
How can I accomplish this with Scala 2.x macros?
After much investigation and getting inspiration from bwmcadams /
supreme-macro-adventure, it looks like one solution is based on the combination of Macro Paradise and the creation of an #ADT annotation.
Macro paradise provides a mechanism to expand annotations on ADTs to rewrite them, thanks to the macroTransform function.
import scala.annotation.{compileTimeOnly, StaticAnnotation}
import scala.language.experimental.macros
import scala.reflect.macros.whitebox.Context
#compileTimeOnly("enable macro paradise to expand macro annotations")
class ADT extends StaticAnnotation {
def macroTransform(annottees: Any*): Any = macro ADT.impl
}
object ADT {
def impl(c: Context)(annottees: c.Expr[Any]*): c.Expr[Any] = {
import c.universe._
val trees = annottees.map(_.tree)
val rewritten = trees match {
case (cd: ClassDef) :: q"object $name { ..$body }" :: Nil =>
$body match {
case q"case object $name extends $_($literal, $_)" :: tail =>
[...]
}
case _ =>
trees
}
c.Expr[Any](q"{..$rewritten}")
}
}
With the help of quasiquotes, one can navigate $body and pattern match the different cases to access the arguments passed to the parent class (here $literal). Finally, one returns the rewritten ADT.
Let's say I have case classes something like below.
trait Foo {
def a: String
}
case class Bar(a: String,b: Option[Int]) extends Foo{
def this(test: Test) = this(test.foo,None)
}
case class Buzz(a: String,b: Boolean) extends Foo{
def this(test: Test) = this(test.foo,false)
}
I'm using the constructor def this(test: Test) via reflection and working as I expected.
A method signature that I use the constructor is something like this
def test[T <: Foo: ClassTag](cb: (String) => Future[T]): Future[Result]
What I want to do is restrict that any case classes that extends trait Foo needs to have def this(test: Test).And the case if any of them don't have it, It should be a compile error.
My attempt
//Compile error
trait Foo[T] {
def a: String
def this(test: Test):T
}
Is there any way to do this?
Thanks in advance.
It is not possible to use the type system to enforce that a class has a specific constructor. This shouldn't really be a surprise, because you're already using reflection to access said constructor. Using a reflective call, the only way to check for the appropriate constructor would be to use more reflection--preferably via a macro to mail compilation fail.
There is almost always a better way than using reflection, though. In this case, we can use a type class to find the correct method that can build a sub-type of Foo (or anything, really) from a Test.
Let's assume Test looks like this:
case class Test(foo: String)
Then, we define a TestBuilder type class, which can provide evidence that we can build an A from a Test.
trait TestBuilder[A] {
def build(test: Test): A
}
// Convenience method for creating type class instances
object TestBuilder {
def apply[A](f: Test => A): TestBuilder[A] = new TestBuilder[A] {
def build(test: Test): A = f(test)
}
}
Then, we define out Foos, each with an instance of TestBuilder[A], where A is the type of each Foo:
trait Foo {
def a: String
}
case class Bar(a: String, b: Option[Int]) extends Foo
object Bar {
implicit val builder = TestBuilder(test => Bar(test.foo, None))
}
case class Buzz(a: String, b: Boolean) extends Foo
object Buzz {
implicit val builder = TestBuilder(test => Buzz(test.foo, false))
}
Note that we no longer need the alternate constructors, and rely on the type class instances to build our Foos using apply.
Now, your test method could look something like this. I changed around the return types because you don't define any implementation or what Result is, but the idea is the same.
def test[T <: Foo : ClassTag : TestBuilder](cb: String => Future[T]): Future[T] = {
val test = Test("abc")
// use the implicitly resolved type class to build `T` from a `Test`
val t = implicitly[TestBuilder[T]].build(test)
Future(t).andThen {
case Success(x) => cb(x.a)
}
}
Now, something like this will compile:
// T is Bar
scala> test((s: String) => Future(Bar(s, None)))
res0: scala.concurrent.Future[Bar] = scala.concurrent.impl.Promise$DefaultPromise#56f2bbea
And using some other type Baz, without an instance of TestBuilder[Baz] will fail.
case class Baz(a: String) extends Foo
scala> test((s: String) => Future(Baz(s)))
<console>:29: error: could not find implicit value for evidence parameter of type TestBuilder[Baz]
test((s: String) => Future(Baz(s)))
^
I don't think you can do quite what you're looking for. But maybe this would work for you:
trait Foo {
def a: String
def create(a: String): Foo
}
case class Bar(a: String,b: Option[Int]) extends Foo{
def create(a: String) = Bar(a,None)
}
case class Buzz(a: String,b: Boolean) extends Foo{
def create(a: String) = Buzz(a,false)
}
You would then have a way to construct a Bar or Buzz without having to specify the second parameter.
BTW, I didn't quite follow your template exactly because I didn't know what Test was supposed to be.
I don't think there's a way to do this directly. But one usually constructs case classes through factories -- their companion objects -- and that gives you the flexibility to do what you want in a different way.
Define
trait Test {
def foo : String = ???
}
abstract class Foo[T <: Foo[T]]()(implicit ev : FooMaker[T]) {
def a: String
}
trait FooMaker[T <: Foo[T]] {
def apply( test : Test ) : T
}
implicit object Bar extends FooMaker[Bar] {
def apply(test: Test) = Bar(test.foo,None)
}
case class Bar(a: String,b: Option[Int]) extends Foo[Bar]
implicit object Buzz extends FooMaker[Buzz] {
def apply(test: Test) = Buzz(test.foo,false)
}
case class Buzz(a: String,b: Boolean) extends Foo[Buzz]
But if you try to define a Foo without the factory method in the companion object that you require:
case class Barf(a : String, b : Short ) extends Foo[Barf]
You'll see
scala> case class Barf(a : String, b : Short ) extends Foo[Barf]
<console>:12: error: could not find implicit value for parameter ev: FooMaker[Barf]
case class Barf(a : String, b : Short ) extends Foo[Barf]
Add the companion object with the factory you need, and it's all good
implicit object Barf extends FooMaker[Barf] {
def apply(test: Test) = Barf(test.foo,0.toShort)
}
case class Barf(a : String, b : Short ) extends Foo[Barf]
In the REPL:
scala> :paste
// Entering paste mode (ctrl-D to finish)
implicit object Barf extends FooMaker[Barf] {
def apply(test: Test) = Barf(test.foo,0.toShort)
}
case class Barf(a : String, b : Short ) extends Foo[Barf]
// Exiting paste mode, now interpreting.
defined object Barf
defined class Barf
Note that to compile this stuff in the REPL you'll need to use :paste because the mutually interdependent definitions can't be defined separately.
This Question is a consequence of the Question How to define an abstract copyable superclass for any case class but one can leave that context alone and focus on this:
NOTE: The whole compiling code base (with Scala 2.11.8) can be accessed in github play-authenticate-usage-scala
I have a trait that use shapeless and is defined as (note the implicit mkLens):
import shapeless._, tag.##
import shapeless._
import tag.$at$at
trait AutoIncEntity[PK, E <: AutoIncEntity[PK, E]] extends Entity[PK] { self: E =>
def copyWithNewId(id : PK)(implicit mkLens: MkFieldLens.Aux[E, Symbol ## Witness.`"id"`.T, PK]) : E = {
(lens[E] >> 'id).set(self)(id)
}
}
All the complexity is basically to say: Any case class (like those Rows auto-generated by Slick) by extending this trait, offer a base reusable implementation of copyWithNewId(id). This method simply delegates to the copy(id = id) method which is case class compiler generated and can not be abstracted away or "pulled up". For example, UserRow by extending AutoIncEntity can be used as part of a framework that builds on top of AutoIncEntity:
case class UserRow(id: Long, firstName: Option[String] = None,
middleName: Option[String] = None, lastName: Option[String] = None)
extends AutoIncEntity[Long, UserRow]
Now I use AutoIncEntity to build a generic Dao that inserts a new record and at the same time fetches the user entity from the database including the new auto generated id:
abstract class GenericDaoAutoIncImpl[T <: Table[E] with IdentifyableTable[PK], E <: AutoIncEntity[PK, E], PK: BaseColumnType]
(dbConfigProvider: DatabaseConfigProvider, tableQuery: TableQuery[T]) extends GenericDaoImpl[T, E, PK](dbConfigProvider, tableQuery)
with GenericDaoAutoInc[T, E, PK] {
override def createAndFetch(entity: E)(implicit mkLens: MkFieldLens.Aux[E, Symbol ## Witness.`"id"`.T, PK]): Future[Option[E]] = {
val insertQuery = tableQuery returning tableQuery.map(_.id) into ((row, id) => row.copyWithNewId(id))
db.run((insertQuery += entity).flatMap(row => findById(row.id)))
}
}
Now the question is how can I modify this solution to avoid propagating/copy-pasting the "voodoo" implicit parameter (implicit mkLens: MkFieldLens.Aux[E, Symbol ## Witness."id".T, PK])? and the corresponding needed "voodoo" imports?
An example case class: Was trying to create a generic query builder
case class BaseQuery(operand: String, value: String)
case class ContactQuery(phone: BaseQuery, address: BaseQuery)
case class UserQuery(id: BaseQuery, name: BaseQuery, contact: ContactQuery)
val user = UserQuery(BaseQuery("equal","1"), BaseQuery("like","Foo"), ContactQuery(BaseQuery("eq","007-0000"),BaseQuery("like", "Foo City")))
//case class Contact(phone: String, address: String)
//case class User(id: Long, name: String, contact: Contact)
//val user = User(1, "Foo Dev", Contact("007-0000","Foo City"))
How can we retrieve the field names and respective values in scala,
On further research,
Solutions using Scala Reflection:
def classAccessors[T: TypeTag]: List[MethodSymbol] = typeOf[T].members.collect {
case m: MethodSymbol if m.isCaseAccessor => m
}.toList
// The above snippet returns the field names, and as input we have to
//feed the 'TypeTag' of the case class. And since we are only feeding a
//TypeTag we will not have access to any object values. Is there any Scala
// Reflection variant of the solution.
Another solution,
def getMapFromCaseClass(cc: AnyRef) =
(scala.collection.mutable.Map[String, Any]() /: cc.getClass.getDeclaredFields)
{
(a, f) =>
f.setAccessible(true)
a + (f.getName -> f.get(cc))
}
// The above snippet returns a Map[String, Any] if we feed the case class
//object. And we will need to match the map value to any of our other case
//classes. If the class structure were simple, the above solution would be
//helpful, but in case of complex case class this would not be the most efficient solution.
Trying to:
I am actually trying to retrieve the list of field and their values during runtime.
One of the use cases,
val list: Seq[Somehow(Field+Value)] = listingFieldWithValue(obj: UserQuery)
for(o <- list){
o.field.type match{
case typeOne: FooType =>{
//Do something
}
case typeTwo: FooBarType =>{
//Do something else
}
}
}
Not really scala-reflect solution, but shapeless one. Shapeless is built on top of implicit macro, so it way faster than any reflection, if you have type information at compile time.
For implementation of your updated requirements you'll need some time to carry needed type information
sealed trait TypeInfo[T]{
//include here thing you like to handle at runtime
}
Next you can define such info for different types and provide implicit resolution. In my example such implementation are also suitable for later matching
implicit case object StringField extends TypeInfo[String]
case class NumericField[N](implicit val num: Numeric[N]) extends TypeInfo[N]
implicit def numericField[N](implicit num: Numeric[N]): TypeInfo[N] = new NumericField[N]
case class ListField[E]() extends TypeInfo[List[E]]
implicit def listField[E] = new ListField[E]
Then we define more suitable for pattern matching result structure
sealed trait FieldDef
case class PlainField[T](value: Any, info: TypeInfo[T]) extends FieldDef
case class EmbeddedType(values: Map[Symbol, FieldDef]) extends FieldDef
So any result will be either value container with needed type info or container for deeper look.
Finally we can define concept implementation
import shapeless._
import shapeless.labelled.FieldType
import shapeless.ops.hlist.{ToTraversable, Mapper}
sealed abstract class ClassAccessors[C] {
def apply(c: C): Map[Symbol, FieldDef]
}
trait LowPriorClassInfo extends Poly1 {
implicit def fieldInfo[K <: Symbol, V](implicit witness: Witness.Aux[K], info: TypeInfo[V]) =
at[FieldType[K, V]](f => (witness.value: Symbol, PlainField(f, info)))
}
object classInfo extends LowPriorClassInfo {
implicit def recurseInfo[K <: Symbol, V](implicit witness: Witness.Aux[K], acc: ClassAccessors[V]) =
at[FieldType[K, V]](f => (witness.value: Symbol, EmbeddedType(acc(f))))
}
implicit def provideClassAccessors[C, L <: HList, ML <: HList]
(implicit lgen: LabelledGeneric.Aux[C, L],
map: Mapper.Aux[classInfo.type, L, ML],
toList: ToTraversable.Aux[ML, List, (Symbol, FieldDef)]) =
new ClassAccessors[C] {
def apply(c: C) = toList(map(lgen.to(c))).toMap
}
def classAccessors[C](c: C)(implicit acc: ClassAccessors[C]) = acc(c)
now
classAccessors(User(100, "Miles Sabin", Contact("+1 234 567 890", "Earth, TypeLevel Inc., 10")))
will result to
Map(
'id -> PlainField(100, NumericField( scala.math.Numeric$LongIsIntegral$#...)),
'name -> PlainField("Miles Sabin", StringField),
'contact -> EmbeddedType( Map(
'phone -> PlainField( "+1 234 567 890", StringField),
'address -> PlainField("Earth, TypeLevel Inc., 10", StringField))))
I want to use macro annotations (macro-paradise, Scala 2.11) to generate synthetic traits within an annotated trait's companion object. For example, given some STM abstraction:
trait Var[Tx, A] {
def apply() (implicit tx: Tx): A
def update(value: A)(implicit tx: Tx): Unit
}
I want to define a macro annotation txn such that:
#txn trait Cell[A] {
val value: A
var next: Option[Cell[A]]
}
Will be re-synthesised into:
object Cell {
trait Txn[-Tx, A] {
def value: A
def next: Var[Option[Cell.Txn[Tx, A]]] // !
}
}
trait Cell[A] {
val value: A
var next: Option[Cell[A]]
}
I got as far as producing the companion object, the inner trait, and the value member. But obviously, in order for the next member to have the augmented type (instead of Option[Cell[A]], I need Option[Cell.Txn[Tx, A]]), I need to pattern match the type tree and rewrite it.
For example, say I find the next value definition in the original Cell trait like this:
case v # ValDef(vMods, vName, tpt, rhs) =>
How can I analyse tpt recursively to rewrite any type X[...] being annotated with #txn to X.Txn[Tx, ...]? Is this even possible, given like in the above example that X is yet to be processed? Should I modify Cell to mix-in a marker trait to be detected?
So the pattern matching function could start like this:
val tpt1 = tpt match {
case tq"$ident" => $ident // obviously don't change this?
case ??? => ???
}
I would like to preface my answer with the disclaimer that this kind of stuff is not easy to do in current Scala. In an ideal macro system, we would like to typecheck tpt in its lexical context, then walk through the structure of the resulting type replacing X[A] with X.Txn[Tx, A] for those X that are subtypes of TxnMarker, and then use the resulting type in the macro expansion.
However, this kind of happy mixing of untyped trees (that come into macro annotations) and typed trees (that typechecker emits) is incompatible with how compiler internals work (some details about that can be found in Scala macros: What is the difference between typed (aka typechecked) an untyped Trees), so we'll have to approximate.
This will be an approximation, because both in 2.10 and 2.11 our macros are unhygienic, meaning that they are vulnerable to name clashes (e.g. in the final expansion tree Var in Var[...] could bind to something unrelated if e.g. that trait we're rewriting contains a type member called Var). Unfortunately at the moment there's just one way to address this problem robustly, and it is very-very hard to carry out without deep understanding of compiler internals, so I'm not going into those details here.
import scala.reflect.macros.whitebox._
import scala.language.experimental.macros
import scala.annotation.StaticAnnotation
trait Var[T]
trait TxnMarker
object txnMacro {
def impl(c: Context)(annottees: c.Expr[Any]*): c.Expr[Any] = {
import c.universe._
// NOTE: this pattern is only going to work with simple traits
// for a full pattern that captures all traits, refer to Denys's quasiquote guide:
// http://den.sh/quasiquotes.html#defns-summary
val q"$mods trait $name[..$targs] extends ..$parents { ..$stats }" = annottees.head.tree
def rewire(tpt: Tree): Tree = {
object RewireTransformer extends Transformer {
override def transform(tree: Tree): Tree = tree match {
case AppliedTypeTree(x # RefTree(xqual, xname), a :: Nil) =>
val dummyType = q"type SomeUniqueName[T] = $x[T]"
val dummyTrait = q"$mods trait $name[..$targs] extends ..$parents { ..${stats :+ dummyType} }"
val dummyTrait1 = c.typecheck(dummyTrait)
val q"$_ trait $_[..$_] extends ..$_ { ..${_ :+ dummyType1} }" = dummyTrait1
def refersToSelf = dummyTrait1.symbol == dummyType1.symbol.info.typeSymbol
def refersToSubtypeOfTxnMarker = dummyType1.symbol.info.baseClasses.contains(symbolOf[TxnMarker])
if (refersToSelf || refersToSubtypeOfTxnMarker) transform(tq"${RefTree(xqual, xname.toTermName)}.Txn[Tx, $a]")
else super.transform(tree)
case _ =>
super.transform(tree)
}
}
RewireTransformer.transform(tpt)
}
val stats1 = stats map {
// this is a simplification, probably you'll also want to do recursive rewiring and whatnot
// but I'm omitting that here to focus on the question at hand
case q"$mods val $name: $tpt = $_" => q"$mods def $name: $tpt"
case q"$mods var $name: $tpt = $_" => q"$mods def $name: Var[${rewire(tpt)}]"
case stat => stat
}
val annottee1 = q"$mods trait $name[..$targs] extends ..${parents :+ tq"TxnMarker"} { ..$stats }"
val companion = q"""
object ${name.toTermName} {
trait Txn[Tx, A] { ..$stats1 }
}
"""
c.Expr[Any](Block(List(annottee1, companion), Literal(Constant(()))))
}
}
class txn extends StaticAnnotation {
def macroTransform(annottees: Any*): Any = macro txnMacro.impl
}
Actually, while I was writing this macro, I realized that it is ill-equipped to deal with cyclic dependencies of #txn-annotated definitions. The info.baseClasses.contains(symbolOf[TxnMarker]) check essentially forces expansion of the class/trait referred to in info, so the macro is going to loop. This won't lead to a SOE or a freeze though - scalac will just produce a cyclic reference error and bail out.
At the moment I've no idea how to address this problem purely with macros. Maybe you could leave the code generation part in an annotation macro and then move the type transformation part into a fundep materializer. Oh right, it seems that it might work! Instead of generating
object Cell {
trait Txn[-Tx, A] {
def value: A
def next: Var[Option[Cell.Txn[Tx, A]]]
}
}
trait Cell[A] {
val value: A
var next: Option[Cell[A]]
}
You could actually generate this:
object Cell {
trait Txn[-Tx, A] {
def value: A
def next[U](implicit ev: TxnTypeMapper[Option[Cell[A]], U]): U
}
}
trait Cell[A] {
val value: A
var next: Option[Cell[A]]
}
And TxnTypeMapper[T, U] could be summoned by a fundep materializer macro that would do the Type => Type transformation using Type.map, and that one won't lead to cyclic reference errors, because by the time a materializer is invoked (during typer), all macro annotations will have already expanded. Unfortunately, I don't have time to elaborate at the moment, but this looks doable!!