On Fri, 10 Jun 2022 at 14:10, Sumanth Rajkumar <rajkumar.suma...@gmail.com>
wrote:

> For 1) I ran mvn verify and found the following errors
>
>
> org.apache.commons.numbers.complex.Complex.getImaginary():METHOD_NOW_ABSTRACT,
> org.apache.commons.numbers.complex.Complex.getReal():METHOD_NOW_ABSTRACT,
> org.apache.commons.numbers.complex.Complex:CLASS_NOW_ABSTRACT,
> org.apache.commons.numbers.complex.Complex:CLASS_TYPE_CHANGED,
>
> org.apache.commons.numbers.complex.ComplexCartesianImpl:METHOD_ABSTRACT_ADDED_IN_IMPLEMENTED_INTERFACE,
>
> org.apache.commons.numbers.complex.ComplexList:METHOD_ABSTRACT_ADDED_IN_IMPLEMENTED_INTERFACE,
>
> org.apache.commons.numbers.complex.ImmutableComplexList:METHOD_ABSTRACT_ADDED_IN_IMPLEMENTED_INTERFACE
>
> These are expected changes... Is there a compatibility issue here?
>

Yes. These are reported as errors.

One point here is that Complex is a final class. So some of the errors
regarding inheritance are non-issues. However binary compatibility requires
that a class compiled against the old version can run against the new one.
The main issue is changing a class to an interface (type change).

The japicmp plugin does not have a lot of documentation. You can try revapi
instead. Put this in the plugins section of the pom.xml:

      <plugin>
        <groupId>org.revapi</groupId>
        <artifactId>revapi-maven-plugin</artifactId>
        <version>0.14.6</version>
        <dependencies>
          <dependency>
            <groupId>org.revapi</groupId>
            <artifactId>revapi-java</artifactId>
            <version>0.26.1</version>
          </dependency>
        </dependencies>
      </plugin>

Then run:

mvn revapi:check  (if you have the jar package)
mvn package revapi:check -DskipTests -Djavadoc.skip      (if you don't)

This will output some similar compatibility errors and link to online
documentation that explains why it is a problem.

This is the main issue:

https://revapi.org/revapi-java/differences.html#java.class.kindChanged

Changing a class to an interface. In this case methods on the object are
invoked using a different instruction.

Save this as Test.java:

public class Test {
  static class A {
    public int getAnswer() { return 42; }
  }

  interface B {
    int getAnswer();
  }

  static class Bimp implements B {
    public int getAnswer() { return 13; }
  }

  public static void main(String[] args) {
    A a = new A();
    System.out.println(a.getAnswer());
    B b = new Bimp();
    System.out.println(b.getAnswer());
  }
}

> javac Test.java
> java Test
42
13
> javap -c Test
...

12: invokevirtual #16                 // Method Test$A.getAnswer:()I
...

30: invokeinterface #29,  1           // InterfaceMethod
Test$B.getAnswer:()I
...

Here we see the interface method uses 'invokeinterface' and the class
method uses 'invokevirtual'.

So if you change class A to an interface then Test will have a runtime
linkage error as it cannot find the method (this is all assuming that A, B
and Bimp are in their own class files which I didn't do here for
simplicity). Basically if a class thinks the object with a method is a
class and it is changed on the classpath at runtime to an interface this
will not work.


Thus we have to keep Complex as a class. However it does not mean the
methods cannot be moved to e.g.

public final class ComplexFunctions {
    interface ComplexResult<R> {
        R accept(double real, double imag);
    }

    public static <R> R conj(double real, double imaginary,
ComplexResult<R> result) {
        return result.accept(real, -imaginary);
    }
}

And Complex changed to e.g:

    ComplexFunctions conj() {
        return ComplexMath.conj(real(), imag(), Complex::ofCartesian);
    }

Reply via email to