-
Notifications
You must be signed in to change notification settings - Fork 1
Tutorial ~ Example (Part 1)
This section will transform the code shown in [the introduction](https://github.com/miniboxing/ildl-plugin/wiki/Tutorial-~-Introduction) using the `ildl-plugin`. If you have either the [demo virtual machine](https://github.com/miniboxing/ildl-plugin/wiki/Setup-%7E-VM) or have [set up `ildl-plugin` locally](https://github.com/miniboxing/ildl-plugin/wiki/Setup-%7E-Local), you can use the `ildl-scalac` runner script to execute the code on your machine.
Let us take a small 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)
}
}If we compile this code, we get:
$ ildl-scalac example.scala
$ ildl-scala Test
(5,13)
(-34,34)
So far, so good. Let's now assume we heard from a fellow programmer that tuples are inefficient and that we could encode our complex numbers as long integers. The first step would be to change the alias:
type Complex = LongNow, suddenly, none of our code compiles anymore:
$ ildl-scalac example.scala
example.scala:7: error: value _1 is not a member of Test.Complex
def +(p2: Complex): Complex = (p1._1 + p2._1 , p1._2 + p2._2)
^
...
example.scala:16: error: type mismatch;
found : (Int, Int)
required: Test.Complex
(which expands to) Long
val x2: Complex = (2, 8)
^
14 errors found
An instinct would be to define implicit conversions from what we previously had, pairs of integers to long integers and back:
// implicit conversions:
import language.implicitConversions
implicit def intPairToComplex(p: (Int, Int)): Complex =
(p._1.toLong << 32l) | (p._2.toLong & 0xFFFFFFFFl)
implicit def complexToIntPair(c: Complex): (Int, Int) =
((c >>> 32).toInt, (c & 0xFFFFFFFF).toInt)Great, with these implicit conversions, our program compiles again:
$ ildl-scalac example.scala
$ ildl-scala Test
21474836493
146028888104
But wait! What are those results?!? Those are not our resulting complex numbers! Of course, we need to convert back to complex numbers before printing:
println(complexToIntPair(x1 + x2))
println(complexToIntPair(x1 * x2))Now, with these lines, our program became twice as large:
object Test {
// "define" type complex based on integer pairs
type Complex = Long
// 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...
}
// implicit conversions
import language.implicitConversions
implicit def intPairToComplex(p: (Int, Int)): Complex =
(p._1.toLong << 32l) | (p._2.toLong & 0xFFFFFFFFl)
implicit def complexToIntPair(c: Complex): (Int, Int) =
((c >>> 32).toInt, (c & 0xFFFFFFFF).toInt)
// test the output
def main(args: Array[String]): Unit = {
val x1: Complex = (3, 5)
val x2: Complex = (2, 8)
println(complexToIntPair(x1 + x2))
println(complexToIntPair(x1 * x2))
}
}Let's compile and run now:
$ ildl-scalac example.scala
$ ildl-scala Test
(5,13)
(34,40)
Wait, what? Still wrong? Yes, because long integers have + and * operations of their own, so the IntPairAsComplex methods are not being invoked anymore. While we started with a toy example, it is clear that refactoring by hand is tedious and very error-prone, even with the advanced features of Scala, such as implicit conversions. Furthermore, we have to introduce different artifacts in the code, which makes it lose its high level.
- continue with the example, part two
- return to the main page
Now, how would
ildl-pluginwork here? Let's find out in part two.
The `ildl-plugin` is a meta-programming technique aimed at allowing safe, custom transformations across library boundaries. Using `ildl`-based transformations, we were able to obtain speedups in excess of 20x and have optimized code across a wide range of use-cases. **Return to the main page** or **return to the OOPSLA Step by Step Guide**
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).