Skip to content

Tutorial ~ Example (Part 1)

Vlad Ureche edited this page Jun 9, 2015 · 15 revisions
ildl logo 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 = Long

Now, 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 this toy example, it becomes clear that refactoring by hand is tedious and very error-prone. Furthermore, we have to introduce different artifacts in the code, which makes it lose its high level.

Now, how would ildl-plugin work here? Let's find out in part two.

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