3

I am trying to write a function which fills an array with a given value using scala macros. For instance a call to:

val ary = Array( 0, 1, 2 )
fill3( ary, 50+25 )

should be expanded to:

val ary = Array(0, 1, 2 )
{
  val $value = 50+25
  ary(0) = $value
  ary(1) = $value
  ary(2) = $value       
}

Here is my first attempt:

def fill3( ary: Array[Int], x: Int ) = macro fill_impl3

def fill_impl3( c: Context )
( ary: c.Expr[Array[Int]], x: c.Expr[Int]): c.Expr[Unit] = {
  import c.universe._        
  def const(x:Int) = Literal(Constant(x))

  //Precompute x
  val valName = newTermName("$value")
  val valdef = ValDef( Modifiers(), valName, TypeTree(typeOf[Int]), x.tree )

  val updates = List.tabulate( 3 ){
  i => Apply( Select( ary.tree, "update"), List( const(i), ??? ) )
  }

  val insts = valdef :: updates
  c.Expr[Unit](Block(insts:_*))
}

But here I'm stuck for two reasons:

  1. I don't know hot to get the precomputed value ($value)
  2. I need several of these function for Arrays of size 3, 4, 6, 9 and 27. Is there a way to dry the definitions, or should I write fill3, fill4, fill6, etc.

Is there the right way to proceed ? How can I solve my two problems ?

EDIT: I realized my initial question was stupid because the size must be known at compile time...

6
  • Is the size of the array known at compile time? Commented Aug 18, 2012 at 12:28
  • I just updated the question to clarify this point. I simplified the problem with a fixed size. Commented Aug 18, 2012 at 12:29
  • 1
    What would be the benefit of using a macro here? Commented Aug 18, 2012 at 12:32
  • And is the value known at compile time or can it be some arbitrary expression? Commented Aug 18, 2012 at 12:37
  • @kimstebel 1. Learning macros. 2. I am rewriting a numerical intensive code that uses lots of computations on small size arrays (size known at compile time). I would like to see if I can gain some speed-up by unrolling all loops to avoid incrementing counters and the bound check. I plan to write vector operations this way. Commented Aug 18, 2012 at 12:37

2 Answers 2

2
def fill(size:Int, ary: Array[Int], x: Int ) = macro fill_impl

def fill_impl( c: Context )
(size:c.Expr[Int], ary: c.Expr[Array[Int]], x: c.Expr[Int]): c.Expr[Unit] = {
  import c.universe._        
  def const(x:Int) = Literal(Constant(x))

  val Literal(Constant(arySize:Int)) = size.tree

  //Precompute x
  val valName = newTermName("$value")
  val valdef = ValDef( Modifiers(), valName, TypeTree(typeOf[Int]), x.tree )

  val updates = List.tabulate( arySize ){
  i => Apply( Select( ary.tree, "update"), List( const(i), Ident(valName) ) )
  }

  val insts = valdef :: updates
  c.Expr[Unit](Block(insts:_*))
}
Sign up to request clarification or add additional context in comments.

3 Comments

that is strange, I am using M6 too. Is your project available somewhere?
how do you compile that without splitting it into subprojects?
I will split it in subprojects, but currently I stupidly comment the main method and when then macro compiles I uncomment it...
0

You can try to figure it out by using reify along with printing the raw tree of its result:

def fill_impl3( c: Context )
( ary: c.Expr[Array[Int]], x: c.Expr[Int]): c.Expr[Unit] = {
  import c.universe._
  val r = reify {
     val $value = x.splice
     val $arr  = ary.splice
     $arr(0)   = $value
     $arr(1)   = $value
     $arr(2)   = $value
  }
  println( showRaw( r.tree ))
  r
}

Which gives something like

val vt = newTermName("$value")
val at = newTermName("$arr")
val ut = newTermName("update")
Block(List(
  ValDef(Modifiers(), vt, TypeTree(), ...),
  ValDef(Modifiers(), at, TypeTree(), ...),
  Apply(Select(Ident(at), ut), List(Literal(Constant(0)), Ident(vt))),
  Apply(Select(Ident(at), ut), List(Literal(Constant(1)), Ident(vt)))),
  Apply(Select(Ident(at), ut), List(Literal(Constant(2)), Ident(vt)))
)

1 Comment

Do not use $ on identifiers! They are reserved for the compiler, and reifying already protects you from identifier clash.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.