About open question on fastutil

29 views
Skip to first unread message

Richard Gomes

unread,
Sep 18, 2008, 8:39:59 AM9/18/08
to JAVAWUG
Hi ALL :)

Thank you all for your interest on JQuantLib and also for your
supporting words which refuel us with energy to go ahead.

Yesterday we had a question regarding boxing/autoboxing when we use
classes from fastutil package.
Oh well, I had a look at the sources. Before going ahead, let me
explaing some details which may be useful for those interested on
studying it.

After you obtain and uncompress fastutil source package, you need to
run

make sources

in order to generate .java sources which you need to build the huge
fastutil JAR file.

It works like this:

A preprocessor is used in order to expand template files into actual
code, which will, in a nutshell, replace definitions by actual
primitive types and/or class depending on the situation. Only the pre-
processing step of gcc (C compiler) is needed. Then .c files are
renamed to .java. That's it. After that, you can compile .java
sources.

Going back to the question.

The question was "How add(double d) can be used if List interface
defines add(Double d) and not add(double d)".

The answer is:

fastutil implements not only the List interface we know but they also
implements other interfaces defined in fastutil package. These
interfaces add more methods which intend to add the possibility of
performing method calls without boxing/autoboxing.

See below an example which explains the general idea.
As you can see, we have 2 flavors of add(...).

interface DoubleList {
public boolean add(Double d);
}

interface doubleList {
public boolean add(double d);
}

class MyDoubleArrayList implements DoubleList, doubleList {

@Override
public boolean add(double d) {
return false; // It's only an example!
}

@Override
public boolean add(Double d) {
return add(d.doubleValue ());
}

}


Thanks

Joel L

unread,
Sep 20, 2008, 4:25:54 AM9/20/08
to JAVAWUG
I think what had people confused was that your example used a List
(which I assume was a java.util.List). If I'm remembering correctly:

List thelist = new DoubleArrayList();
thelist.add(3.4); // no autoboxing?

The problem is List only has add(Object) and it seems doubtful you
could avoid autoboxing if 'thelist' is declared as a java.util.List.
Perhaps it was just a typo, and should have been:

doubleList theList = new DoubleArrayList()

?

Thanks for the great talk on Wednesday btw!

-Joel

Phil Haigh

unread,
Sep 20, 2008, 5:00:29 AM9/20/08
to jav...@googlegroups.com
Or, even...

DoubleList theList = ...

Phil.

Richard Gomes

unread,
Sep 25, 2008, 7:40:20 PM9/25/08
to JAVAWUG
Hi Joel, Hi Phil

You guys are absolutely right. We need to use the add() method from
DoubleListArray and not the add() from List interface.

List list = DoubleArrayList(); // backed by an array of doubles
list.add(1.0); // autoboxing :: list.add(new Double(1.0))
(DoubleArrayList)list.add(2.0); // no autoboxing
double d = (DoubleArrayList)list.getDouble(0);

Thanks a lot for pointing out my mistake.
I've fixed the slides and notes.

Now I have to figure out how to avoid the same mistake in our code.
The use of interfaces is elegant and recommended as a good practice
but the problem is that, in order to avoid autoboxing, we will have to
specify the correct interface, like this:

(DoubleArrayList)list.add(2.0); // no autoboxing

The above line does not look friendly to me.
Programmers will probably forget to specify the correct interface,
which will lead to an autoboxing.

Another possibility is:

DoubleArrayList list = new DoubleArrayList();
list.add(2.0); // no autoboxing

... which is against the recommended best practices.

Something to think. :/

Thanks a lot.

Cheers

Richard


Kind Regards

Richard Gomes

unread,
Sep 27, 2008, 9:21:48 PM9/27/08
to JAVAWUG
Hi ALL,

In the previous post, I've mentioned the need to raise a compilation
error when list.add(Double a) is called.
I cannot say that I found the solution for it yet but at least I've
done one step to solve the problem.

Using Macker we can determine when standard JCF classes are being used
whilst fastutil implementation should be used instead.
In spite it does not solve the mistake which produces unnecessary
autoboxing, at least we can guarantee that are using a high
performance implementation of JCF interfaces.

Below you can see two snippets of code:

1. How this validation is triggered in our pom.xml;
2. Macker rule which detects uses of JCF concrete classes.

I also show some output produced by Macker, which provokes a failure
in the build process.


========= pom.xml =================
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<groupId>org.apache.maven.plugins</groupId>

<dependencies>
<dependency>
<groupId>ant</groupId>
<artifactId>ant-antlr</artifactId>
<version>1.6.5</version>
</dependency>
<dependency>
<groupId>antlr</groupId>
<artifactId>antlrall</artifactId>
<version>2.7.4</version>
</dependency>
<dependency>
<artifactId>macker</artifactId>
<groupId>innig</groupId>
<version>0.4.2</version>
</dependency>
<dependency>
<artifactId>innig-util</artifactId>
<groupId>innig</groupId>
<version>0.4.2</version>
</dependency>
<dependency>
<artifactId>jakarta-regexp</artifactId>
<groupId>jakarta-regexp</groupId>
<version>1.4</version>
</dependency>
<dependency>
<artifactId>bcel</artifactId>
<groupId>bcel</groupId>
<version>5.1</version>
</dependency>
<dependency>
<artifactId>jdom</artifactId>
<groupId>jdom</groupId>
<version>1.0</version>
</dependency>
<dependency>
<artifactId>commons-lang</artifactId>
<groupId>commons-lang</groupId>
<version>1.0.1</version>
</dependency>
</dependencies>

<executions>
<execution>
<id>macker</id>
<phase>process-classes</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<tasks>
<property name="compile_classpath"
refid="maven.compile.classpath" />
<property name="runtime_classpath"
refid="maven.runtime.classpath" />
<property name="test_classpath"
refid="maven.test.classpath" />
<property name="plugin_classpath"
refid="maven.plugin.classpath" />

<path id="compile.classpath">
<pathelement path="$
{compile_classpath}" />
<pathelement path="$
{plugin_classpath}" />
</path>

<taskdef name="macker"

classname="net.innig.macker.ant.MackerAntTask"

classpathref="maven.plugin.classpath" />
<macker>
<classpath
refid="compile.classpath" />
<rules dir="src/main/macker"
includes="*.xml" />
<classes dir="target/classes">
<include name="**/*.class" />
</classes>
</macker>
</tasks>
</configuration>
</execution>
</executions>
</plugin>


=========== Macker rule =============

<?xml version="1.0"?>
<!DOCTYPE macker PUBLIC
"-//innig//DTD Macker 0.4//EN"
"http://innig.net/macker/dtd/macker-0.4.dtd">

<macker>
<ruleset name="jcf-check">

<pattern name="java2-collections">
<include class="java.util.*">
<include class="**Collection*" />
<include class="**List*" />
<include class="**Map**" />
<include class="**Set*">
<exclude class="**.BitSet" />
</include>
<include class="**Array*" />
<include class="**.Iterator" />
</include>
</pattern>

<pattern name="concrete-class">
<exclude filter="interface" />
<exclude filter="abstract-class" />
</pattern>

<pattern name="java2-collections-concrete-class">
<include pattern="java2-collections">
<include pattern="concrete-class" />
</include>
</pattern>

<access-rule>
<message>Performance: use fastutil classes instead of
standard JCF concrete classes.</message>
<deny>
<to pattern="java2-collections-concrete-class" />
</deny>
</access-rule>

</ruleset>
</macker>


====================================

When we run
mvn clean process-classes
the build fails and we obtain something like this:

Do not use JCF concrete classes, use fastutil classes instead.
Illegal reference
from org.jquantlib.testsuite.lang.TypeReferenceTest
to java.util.TreeMap

Do not use JCF concrete classes, use fastutil classes instead.
Illegal reference
from org.jquantlib.testsuite.model.volatility.EstimatorsTest
to java.util.Arrays

Do not use JCF concrete classes, use fastutil classes instead.
Illegal reference
from org.jquantlib.testsuite.time.ScheduleTest
to java.util.ArrayList

Do not use JCF concrete classes, use fastutil classes instead.
Illegal reference
from org.jquantlib.time.AbstractCalendar
to java.util.ArrayList

Do not use JCF concrete classes, use fastutil classes instead.
Illegal reference
from org.jquantlib.time.Schedule
to java.util.ArrayList

Do not use JCF concrete classes, use fastutil classes instead.
Illegal reference
from org.jquantlib.time.Schedule
to java.util.Collections

Do not use JCF concrete classes, use fastutil classes instead.
Illegal reference
from org.jquantlib.time.TimeGrid
to java.util.Collections

Do not use JCF concrete classes, use fastutil classes instead.
Illegal reference
from org.jquantlib.util.DefaultObservable
to java.util.Collections

Have fun

Richard
Reply all
Reply to author
Forward
0 new messages