tags:

views:

45

answers:

1

I am developing a domain-specific application library in Java and C#. I'd like suggestions or experience from those who have done or thought about this. I've expanded (hopefully not too much) below.

These choices are givens (use of J#, Python, etc. is not in-scope). The Java library interfaces with a large Open community with many complementary libraries/applications, and the C# is hoping to grow similar functionality using .NET. Ultimately we hope the library will be deployed with roughly identical functionality in both languages and the code will be produced as Open Source, mainly by volunteers but with clear benevolent dictatorship.

Currently the majority of the code is Java (built over many years), with somewhere between 10K to 50K LOC (some obsolete). This continues to be maintained and debugged but with little new functionality. The C# code is essentially a subset of this with a little new functionality. It benefits from implicit and explicit refactoring. Both libraries are supported by unit tests.

The current intention (unless SO convinces me otherwise) is that the code will converge towards a common abstraction. We intend that coding is manual, including conversion, so no automatic code generation (see comments in http://stackoverflow.com/questions/569714/parallel-development-in-java-and-c). SO has already suggested that Java and C# syntax which is identical will run similarly (generics being a possible problem) [http://stackoverflow.com/questions/1508019/identifying-code-that-compiles-in-both-java-and-c-but-runs-differently%5D. I see no option during this convergence other than committed human input with unit tests to avoid regression. Hopefully some of the legacy code can be discarded as YAGNI.

It is likely that an important aspect of maintenance will be detection of edge cases in the domain, so that when these are discovered changes will be made to both language variants. Edge cases will include things like unpredictable concident points, zero-length strings, graphs with cycles, etc. It's important that when the bug is reported in one language the other volunteers can clone and adapt the test and fix the bug in parallel without too much difficulty.

Here is a typical piece of Java code that happens to be essentially language independent. (We would expect to have identical class names and signatures for much of the library)

public static RealSquareMatrix getCrystallographicOrthogonalisation(
        double[] celleng, double[] angle) {
    RealSquareMatrix orthMat = new RealSquareMatrix(3);
    double dtor = Math.PI / 180.0;
    double sina = Math.sin(dtor * angle[0]);
    double cosa = Math.cos(dtor * angle[0]);
    double sinb = Math.sin(dtor * angle[1]);
    double cosb = Math.cos(dtor * angle[1]);
    double cosg = Math.cos(dtor * angle[2]);
    double cosgstar = (cosa * cosb - cosg) / (sina * sinb);
    double singstar = Math.sqrt(1.0 - cosgstar * cosgstar);
    double[][] omat = orthMat.getMatrix();
    omat[0][0] = celleng[0] * sinb * singstar;
    omat[0][1] = 0.0;
    omat[0][2] = 0.0;
    omat[1][0] = -celleng[0] * sinb * cosgstar;
    omat[1][1] = celleng[1] * sina;
    omat[1][2] = 0.0;
    omat[2][0] = celleng[0] * cosb;
    omat[2][1] = celleng[1] * cosa;
    omat[2][2] = celleng[2];
    return orthMat;
}

(This code should have been tested for bad arguments!!)

I will give our current approach as an answer and ask others to support or criticize it.

A: 

We plan to take the following approach:

  • create wrappers for the unit tests (e.g. TestUtil.IsEqual(a,b) wraps Assert.isEqual(a, b) (Java) and Assert.AreEqual(a, b) (C#)
  • wrap the XML data model (LINQ in C#, XOM in Java) so that signatures appear as similar as possible
  • use as few constructs in each language that are not available in the other. For example not to use ?? or nullable in C#
  • where language constructs must be different (e.g. class inheritance) try to format them so that a global text replace will work. Then rely on the compiler to detect problems.

Here is a typical test for the class in the question. We had to write a special test routine anyway to compare real matrices. The signature is as abstracted as possible.

public void testGetCrystallographicOrthogonalisation() {

    double[] len = { 10.0, 11.0, 12.0 };
    double[] ang = { 80.0, 90.0, 100.0 }; // degrees!
    RealSquareMatrix m = RealSquareMatrix
  .getCrystallographicOrthogonalisation(len, ang);
    RealSquareMatrix mm = new RealSquareMatrix(3, new double[] {
  9.843316493307713, 0.0, 0.0, -1.7632698070846495,
  10.832885283134289, 0.0, 0.0, 1.9101299543362344, 12.0 });
    MatrixTest.assertEquals("orthogonalise", mm, m, 0.000000000001);
}
peter.murray.rust