Skip to content

Tutorial ~ Example (Part 2)

Vlad Ureche edited this page Jun 9, 2015 · 15 revisions
ildl logo We have seen that even on a small example, rewriting the code to its low-level equivalent can easily become a nightmare. In this part we will define a transformation using the `ildl` plugin.

Let us now come back to the original example:

object Test {
  // "define" type complex based on integer pairs
  type Complex = (Int, Int)

  // add the addition and multiplication operation to complex numbers
  implicit class IntPairAsComplex(val p1: Complex) extends AnyVal {
    def +(p2: Complex): Complex = (p1._1 + p2._1 , p1._2 + p2._2)
    def *(p2: Complex): Complex = (p1._1 * p2._1 - p1._2 * p2._2,
                                   p1._1 * p2._2 + p1._2 * p2._1)
    // we could define other operations here as well...
  }

  // test the output
  def main(args: Array[String]): Unit = {
    val x1: Complex = (3, 5)
    val x2: Complex = (2, 8)
    println(x1 + x2)
    println(x1 * x2)
  }
}

And let us define an ildl data transformation:

  import ildl._
  object IntPairAsComplex extends TransformationDescription {
    def toRepr(p: (Int, Int)): Long @high = 
      (p._1.toLong << 32l) | (p._2.toLong & 0xFFFFFFFFl)
    def toHigh(l: Long @high): (Int, Int) = 
      ((l >>> 32).toInt, (l & 0xFFFFFFFF).toInt)
  }

The transformation object looks quite similar to the two implicits we defined in part one, but what should be noted is that once defined, it is reusable in other contexts and can compose with other transformations.

One thing that needs an explanation is the @high annotation present in the code. This marks the types that represent a transformed object: in our case, Long has the long integer semantics while Long @high has the pair of integer semantics. We won't go into many details here, since the @high annotation is better described later on, but each time we transform a type (called the high-level type, (Int, Int) in our case) to another type (called representation type, Long in this case), then the representation type carries the @high annotation.

So far, we just defined a reusable transformation, but we haven't applied it yet. Let us also apply it. Applying the transformation produces the following code, where the main method is wrapped in the adrt keyword with the IntPairAsComplex transformation object:

object Test {
  // "define" type complex based on integer pairs
  type Complex = (Int, Int)

  // add the addition and multiplication operation to complex numbers
  implicit class IntPairAsComplex(val p1: Complex) extends AnyVal {
    def +(p2: Complex): Complex = (p1._1 + p2._1 , p1._2 + p2._2)
    def *(p2: Complex): Complex = (p1._1 * p2._1 - p1._2 * p2._2,
                                   p1._1 * p2._2 + p1._2 * p2._1)
    // we could define other operations here as well...
  }

  import ildl._
  object IntPairAsComplex extends TransformationDescription {
    def toRepr(p: (Int, Int)): Long @high = 
      (p._1.toLong << 32l) | (p._2.toLong & 0xFFFFFFFFl)
    def toHigh(l: Long @high): (Int, Int) = 
      ((l >>> 32).toInt, (l & 0xFFFFFFFF).toInt)
  }

  adrt(IntPairAsComplex) {
    // test the output
    def main(args: Array[String]): Unit = {
      val x1: Complex = (3, 5)
      val x2: Complex = (2, 8)
      println(x1 + x2)
      println(x1 * x2)
    }
  }
}

Compiling and running it, produces the following result:

$ ildl-scalac example.scala
example.scala:24: warning: The new operator can be optimized if you define a public,
non-overloaded and matching constructor method for it in object IntPairAsComplex, 
with the name ctor_Tuple2:
      val x1: Complex = (3, 5)
                        ^
example.scala:25: warning: The new operator can be optimized if you define a public,
non-overloaded and matching constructor method for it in object IntPairAsComplex,
with the name ctor_Tuple2:
      val x2: Complex = (2, 8)
                        ^
example.scala:26: warning: The method + can be optimized if you define a public,
non-overloaded and matching exension method for it in object IntPairAsComplex,
with the name implicit_IntPairAsComplex_+:
      println(x1 + x2)
                 ^
example.scala:27: warning: The method * can be optimized if you define a public,
non-overloaded and matching exension method for it in object IntPairAsComplex,
with the name implicit_IntPairAsComplex_*:
      println(x1 * x2)
                 ^
four warnings found

$ ildl-scala  Test
(5,13)
(-34,34)

While four warnings appeared out of nowhere, the program produced the correct result. In the next part of the example, we will see why the warnings appeared and how to eliminate them.

From Here:

Frog Work Ahead: Some of the pages of this wiki are in flux. If you can't find what you are looking for, please [file a bug](https://github.com/miniboxing/ildl-plugin/issues).
Clone this wiki locally