Scala reflection to instantiate scala.slick.lifted.TableQuery -


i have base trait

trait mybase {   type m   type t <: table[m]   val query: tablequery[t] } 

where tablequery scala.slick.lifted.tablequery

my subclasses instantiate tablequery so:

type m = account type t = accountstable val query = tablequery[t] 

i'd instantiate tablequery in base trait, possibly using lazy val, i.e.

lazy val query: tablequery[t] = {   ... } 

i've been playing around reflection, haven't had luck.

if understand correctly, want able extend mybase defining m , t without having explicitly instantiate tablequery in each derived class.

using reflection not option because use tablequery.apply (as in val query = tablequery[mytable]), , implemented through macro, you've got "runtime vs compile-time" issue.

if absolutely need mybase trait (as opposed class), don't see viable solution. if can turn mybase class and turn m , t type parameters (instead of abstract types), there @ least 1 solution. hinted in related question (how define generic type in scala?), can define type class (say tablequerybuilder) capture call tablequery.apply (at point concrete type known) along implicit macro (say tablequerybuilder.builderfortable) provide instance of type class. can define method (say tablequerybuilder.build) instantiate tablequery, delegate job type class.

// note: tested scala 2.11.0 & slick 3.0.0 import scala.reflect.macros.context import scala.language.experimental.macros object tablequerybuildermacro {   def createbuilderimpl[t<:abstracttable[_]:c.weaktypetag](c: context) = {     import c.universe._     val t = weaktypeof[t]     q"""new tablequerybuilder[$t]{       def apply(): tablequery[$t] = {         tablequery[$t]       }     }"""   } } trait tablequerybuilder[t<:abstracttable[_]] {   def apply(): tablequery[t] } object tablequerybuilder {   implicit def builderfortable[t<:abstracttable[_]]: tablequerybuilder[t] = macro tablequerybuildermacro.createbuilderimpl[t]   def build[t<:abstracttable[_]:tablequerybuilder](): tablequery[t] = implicitly[tablequerybuilder[t]].apply() } 

the net effect don't need anymore know concrete value of type t in order able instantiate tablequery[t], provided have implicit instance of tablequerybuilder[t] in scope. in other words, can shift need know concrete value of t point know it.

mybase (now class) can implemented this:

class mybase[m, t <: table[m] : tablequerybuilder] {   lazy val query: tablequery[t] = tablequerybuilder.build[t] } 

and can extend without need explcitly call tablequery.apply:

class coffees(tag: tag) extends table[(string, double)](tag, "coffees") {   def name = column[string]("cof_name")   def price = column[double]("price")   def * = (name, price) }  class derived extends mybase[(string, double), coffees] // that's it! 

what happens here in derived's constructor, implicit value tablequerybuilder[coffees] implicitly passed mybase's constructor.

the reason why cannot apply pattern if mybase trait pretty mundane: trait constructors cannot have parameters, let alone implicit parameters, there no implicit way pass tablequerybuilder instance.


Comments

Popular posts from this blog

android - MPAndroidChart - How to add Annotations or images to the chart -

javascript - Add class to another page attribute using URL id - Jquery -

firefox - Where is 'webgl.osmesalib' parameter? -