Monday, November 11, 2013

How to make a manager do some real works - javascript prototype, constructor, and instanceof

You probably heard about some ugly parts of javascript including the keyword “instanceof”. Just in case you missed, the followings are what I’m talking about.

new String(“foo”) instanceof String // this yields true
“foo” instanceof String             // this yields false
So some suggest that you stick with your own functions/objects (and classes if you believe they exist in javascript). The following is an example of how to make javascript play nice with classical OO.

function Employee() { this.name = “everyone”; }
function Manager() { this.name = “boss”; }
Manager.prototype = new Employee;
Now you may check that a manager is indeed a Manager and at the same time an Employee:

new Manager() instanceof Manager  // this yields true
new Manager() instanceof Employee // this yields true
So far so good.  Let's introduce worker, you known, the kind that do the real works.

function WorkerBee() { this.name = “worker”; }
WorkerBee.prototype = new Employee;
Let’s check that a worker is indeed a WorkerBee and at the same time an Employee:

new WorkerBee() instanceof WorkerBee // this yields true
new WorkerBee() instanceof Employee  // this yields true
Everything looks good. We have a classical OO inheritance defined using javascript prototypes.

As good citizens of developer community, we always follow some good principles (don’t we).  So to make the entire thing a little DRY,  let’s rearrange them like these:

function Employ() { this.name = “everyone”; }
function Manager() { this.name = “boss”; }
function WorkerBee() { this.name = “worker”; }
Manager.prototype = WorkerBeen.prototype = new Employee;

Satisfied?  (Do I hear some javascript Ninjas murmuring “noooooo…”? Ignore those noises.)  Let’s check them up.

new Manager() instanceof Manager     // true
new Manager() instanceof Employee    // true
new WorkerBee() instanceof WorkerBee // true
new WorkerBee() instanceof Employee  // true
Now the fun part.  Let’s make a manager do some real works:
new Manager() instanceof WorkerBee // this yields true
What?!

Reference

JavaScript Guide - Details of Object Model

Sunday, August 11, 2013

Mixed Scala and Java in Maven Project

Recently we decided to embrace Scala in our Java Maven project here in Maxta Inc. Adding Scala to an existing Java Maven project should be simple with the help of scala-maven-plugin, however there are still some details that need to be taken care of to get it done right.


Add Scala to Maven Project

Leveraging scala-maven-plugin, it is as simple as invoking both compile and testCompile goals. The followings are what I added initially in the pom.xml file.

<properties>
  <scala.version>2.10.2</scala.version>
<properties>
<dependencies>
  <dependency>
    <groupid>org.scala-lang</groupId>
    <artifactid>scala-library</artifactId>
    <version>${scala.version}</version>
  </dependency>
</dependencies>
<pluginManagement>
  <plugins>
    <plugin>
      <groupid>net.alchim31.maven</groupid>
      <artifactid>scala-maven-plugin</artifactid>
      <version>3.1.5</version>
    </plugin>
    <plugin>
      <artifactId>maven-compiler-plugin</artifactId>
      <version>3.1</version>
      <configuration>
        <source>1.7</source>
        <target>1.7</target>
      </configuration>
    </plugin>
    ...
  </plugins>
</pluginManagement>
<build>
  <plugins>
    <plugin>
      <groupId>net.alchim31.maven</groupId>
      <artifactId>scala-maven-plugin</artifactId>
      <executions>
        <execution>
          <id>scala-compile</id>
          <goals>
            <goal>compile</goal>
            <goal>testCompile</goal>
          </goals>
        </execution>
      </executions>
    </plugin>
    ...
  </plugins>
</build>


Note that the maven-compiler-plugin setting already existed in the original project. It's shown here to let you know that the project was using Java 7 and compiled everything to byte code version 51.

Make Scala and Java See Each Other

The above approach has a problem. In the same Maven module, Scala code can see Java code but not the other way around. That is, Java code can not call Scala. If try, you'll get a "cannot find symbol" or similar compiler error. Following scala-maven-plugin documentation, I made changes like this to pom.xml,


<build>
  <plugins>
    <plugin>
      <groupId>net.alchim31.maven</groupId>
      <artifactId>scala-maven-plugin</artifactId>
      <executions>
        <execution>
          <id>scala-compile</id>
          <phase>process-resources</phase>
          <goals>
            <goal>compile</goal>
          </goals>
        </execution>
        <execution>
          <id>scala-test-compile</id>
          <phase>process-test-resources</phase>
          <goals>
            <goal>testCompile</goal>
          </goals>
        </execution>
      </executions>
    </plugin>
    ...
  </plugins>
</build>

With the above changes, I can call from Scala to Java, and Java to Scala. Everything seemed to be working. However there were still a few more problems when I dig deeper:

  1. Scala code were compiled to JVM 1.6 version byte code (major version 50), while Java code were happily compiled to JVM 1.7 byte code (major version 51) as instructed by Maven (see the first code snippets). Scala compiler doesn't take javac "-target" options. The scalac option "-target:jvm-1.7" needs to be provided for byte code version 51 to be generated.
  2. Java code in fact have been compiled twice, first by scala compiler, then by Java compiler. Since Scala compiler already compiles both Java and Scala code, the default maven-compiler-plugin goals should be disabled.
  3. Scala compilation runs on process-resources and process-test-resources phases. It's just too hacky and can be a trouble for future. They should run in the default "compile" and "test-compile" phases.

Scalac Takes All

With the above discoveries, I came up with the last modifications to pom.xml.
<pluginManagement>
  <plugins>
    <plugin>
      <groupid>net.alchim31.maven</groupid>
      <artifactid>scala-maven-plugin</artifactid>
      <version>3.1.5</version>
      <configuration>
        <recompileMode>incremental</recompileMode>
        <args>
          <arg>-target:jvm-1.7</arg>
        </args>
        <javacArgs>
          <javacArg>-source</javacArg><javacArg>1.7</javacArg>
          <javacArg>-target</javacArg><javacArg>1.7</javacArg>
        </javacArgs>
      </configuration>
    </plugin>
    ...
  </plugins>
</pluginManagement>
<build>
  <plugins>
    <plugin>
      <groupId>net.alchim31.maven</groupId>
      <artifactId>scala-maven-plugin</artifactId>
      <executions>
        <execution>
          <id>scala-compile</id>
          <goals>
            <goal>compile</goal>
          </goals>
        </execution>
        <execution>
          <id>scala-test-compile</id>
          <goals>
            <goal>testCompile</goal>
          </goals>
        </execution>
      </executions>
    </plugin>
    <plugin>
      <artifactId>maven-compiler-plugin</artifactId>
      <executions>
        <execution>
          <id>default-compile</id>
          <phase>none</phase>
        </execution>
        <execution>
          <id>default-testCompile</id>
          <phase>none</phase>
        </execution>
      </executions>
    </plugin>
    ...
  </plugins>
</build>
The key points are,
  • The scala-maven-plugin's compile and testCompile goals should run on their respective default phases, i.e. "compile" and "test-compile".
  • The maven-compiler-plugin's "default-compile" and "default-testCompile" are disabled (by setting the phase to "none"). Note the <id>'s of the two executions need to be set exactly to the two specific values.