Scala macro-makes case copy easy to read

Source: Internet
Author: User

PS: haven't written blog for a long time, 1 is not to write, 2 is not what dry. Recently accumulated some things, can be taken out of the sun. Ha ha.

First of all, boss let me simplify the code of case class copy to make it easy to read.

Case Class A (a:string,b:int) Cases Class B (a:a,b:int,c:string) Val B = B (A ("a", 2), 3, "C") B.copy (A.copy (b=2))//above is a simple example, If the case class is multiple nested, it produces a similar//a.copy (B.copy (c.copy (D.copy ...). Extra-long code.

At that time, in order to solve it, searched a lot, ' scala dynamic ' and so on, still did not find the ideal solution, as for the ' macro ', under the pressure and difficulty too much, had to use

Case Class A (A:string,b:int) Case Class B (a:a,b:int,c:string) {def aa=a.a def aa_= (value:string) =this.copy (A.copy (a=v alue))}

This is a relatively lame solution. After that, it's always been a bit of a depression, so the plan is unacceptable, especially knowing that it macro can be solved in a more elegant and elegant way.
So, the road to the toss began. Here is a list of some of the most useful information that individuals consider:
Macro Official Documents
Exploring Scala Macros:map to case Class Conversion
Scala Macros:let our Powers combine!
Learning Scala Macros
Adding Reflection to Scala Macros
Git:underscoreio/essential-macros
Stackoverflow:where can I learn about constructing AST's for Scala macros?

Every contact with a new thing, the most troublesome is the start, is scala macro no exception, the light to create an idea project outside the chain another project is enough, do not support the simultaneous editing of multiple projects in the same directory, now idea out of 14, solve the problem. Here is a list of the BUILD.SBT for the next two items.

Coreorganization: = "Timzaak" Name: = "core" version: = "0.1-snapshot" scalaversion: = "2.11.4" lazy val macrolib = rootproj ECT (File (".. /macrolib ")) lazy val core = project.in (File (". ")). Aggregate (Macrolib). DependsOn (Macrolib)
Macro liborganization: = "Timzaak" Name: = "Macrolib" version: = "1.0.1" scalaversion: = "2.11.4" librarydependencies ++= S EQ ("Org.scala-lang"% "scala-reflect"% Scalaversion.value, "Org.scala-lang"% "Scala-compiler"% scalaversion.val Ue

After the project is built, is Hello World, here is not detailed, interested, click here!

Well, now that the information is over and the project has Hello World, let's start solving the problem. At first, I set the DSL to

Case Class A (A:string,b:int) Case Class B (a:a,b:int,c:string) Val B = B (A ("a", 2), 3, "C") Copy (b.a.a= "New String")//Return B (A (" New String ", 2), 3," C ")

but found that the error. The beginning of knowledgemacroIt's not as powerful as I think, it's not going to change semantics directly, it should be used to generate code in batches and reduce manual duplication of code. Or maybe it's translated intoreason for it.
Well, let's take a step-by-step. First fix how to builda.copy(b.copy(...the problem.
If you want to solve him, you need to know what AST Zhang is. We use the idea provided by worksheet to get it done.

Import Reflect.runtime.universe._case class C (c:string) Case Class A (A:INT,B:STRING,C:C) Val a = A (1, "", C ("")) Showraw ( Reify{a.copy (a=2)}.tree)//apply (select (Ident (Termname ("a$a ...

However, it can only provide us with a reference, or there will be some problems. Learning Scala Macrosprovides a solution. We can use it.
Get AST, the rest is to construct the target code based on the AST and requirements.
just started to construct

Case Class A (A:string,b:int)//case Class B (a:a,b:int,c:string)//val B = B (A ("a", 2), 3, "C")//copy (b.a.a= "New String")/ /--code to construct val $temp = b.a.copy (a= "New String") Val result = B.copy (a= $temp) result

but found, too hard to write,上一行的代码被下一行代码使用,并且需要创建临时变量, and then instead of the recursive notation, remove the temporary variable.

B.copy (A.copy (a= "New String"))

Object casecopy {  def copy (a: any, b:any )   = macro  imp  def imp (C: context) (A: c.expr[any], b: c.expr[any])  =  {    import c.universe._    def reverpath (V: c.Tree,  lis: list[(c.tree, string)]:  list[(c.tree, string)] = {       v match {        case [email  Protected] (Termname (name))  =>           (tag,  Name)  :: lis        case [email protected] (SE,  termname (t))  =>          reverpath (se,  ( tag, t)  :: lis)         case [email protected] (TypeName (name)) =>            (Thi, name)  :: lis         case apply (a,_) =>           reverpath (A,lis)         case block (List (b), _) =           reverpath (B,lis)          case _ =>          c.abort ( v.pos,  "only support case copy ")       }     }    val  (Path, parm)  = reverpath (A.tree, nil). tail.unzip    (Path.init zip parm.tail). Reverse.foldleft (q "$b":  Tree)  {       case  (re,  (p, m))  =>         q "$p. Copy (${termname (m)}= $re) "    }  }} 

run and test the code:

Case Class B (i:int) Case class ABC (A:int, B:b) object CaseC extends App {import tim.casecopy.CaseCopy.copy val abc = a BC (1, B (2)) println (copy (ABC.A, 123))}

the output is unexpectedly () . Look at one side of the code, only to find that the return value is not set, immediately add.

... def Copy[t] (A:any, b:any): T = Macro Imp[t] def Imp[t] (C:context) (A:c.expr[any], B:c.expr[any]): c.expr[t] = {... val re= (path.init zip parm.tail). Reverse.foldleft (q "$b": Tree) {case (re, p, m) = + q "$p. Copy (${TERMN Ame (m)}= $re) "} C.expr[t] (re) ...
Test println (Copy[abc] (ABC.A, 123))

What else is left to solve?
println(copy[ABC](abc.a,"string"))can also be compiled by the. Type is not secure.
We add this decision to the code.

if (! (    B.actualtype<:<a.actualtype) {C.abort (b.tree.pos,s "B:${b.actualtype} must be subtype of A:${a.actualType}") }

Although only 40 lines of code, but the preparation time for more than 40 hours. This makes me miss the ability of JS dynamic generation code!
scala macroAlthough the 11.x is still marked as experimental, but the official commitment in the near future will become the official library, hoping that the use of macro can be reduced by a step.

Scala macro-makes case copy easy to read

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.