Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-devel / 2011-12

JVM: Question regarding converted Java code

6 messages · 3 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Sven Barth

Hello Jonas!

Today I've converted a third party jar file using javapp, which went without problems so far (I only need to convert another jar file, because there is a dependency).
When compiling I noticed a few warnings though:

=== output ===

...
bukkit.inc(1668,5) Warning: Constructor should be public
bukkit.inc(1669,5) Warning: Constructor should be public
bukkit.inc(1749,14) Warning: An inherited method is hidden by "procedure
clone:OBLocation;"
bukkit.inc(1751,14) Warning: An inherited method is hidden by "procedure
clone:JLObject;"
bukkit.inc(2006,5) Warning: Constructor should be public
bukkit.inc(2007,5) Warning: Constructor should be public
bukkit.inc(2046,14) Warning: An inherited method is hidden by "procedure
next:JLObject;"
...

=== output ===

1) as it seems to be a rather usual practice in Java, would it be possible to disable the "Constructor should be public" warnings if the target cpu is the JVM?
2) in the code I converted the classes often seem to "reintroduce" methods that are available in parent classes or implemented interfaces with different result types without declaring the original method though.

E.g.:

=== Java source begin ===

public class Location implements Cloneable {

...

@Override
public Location clone() {
....
}

...

}

=== Java source end ===

is converted to

=== Pascal source begin ===

OBLocation = class external 'org.bukkit' name 'Location' (JLObject, JLCloneable)

   public
     ...
     function clone(): OBLocation; overload; virtual;
     ... // <= other functions between
     function clone(): JLObject; overload; virtual;  // throws

java.lang.CloneNotSupportedException

   end;

=== Pascal source end ===

Is this indeed correct? Does the compiler (or the JVM) indeed call the correct function in the end (in this case org.bukkit.Location.clone)?

[I have not tested what the compiler or the JVM does, I'm just curious at the moment regarding the warnings I get]

Regards,
Sven

Reply by email

Jonas Maebe
to Sven Barth
Sven Barth wrote
1) as it seems to be a rather usual practice in Java, would it be possible to disable the "Constructor should be public" warnings if the target cpu is the JVM?

Yes.

Show quoted text 15 lines
2) in the code I converted the classes often seem to "reintroduce" methods that are available in parent classes or implemented interfaces with different result types without declaring the original method though. === Pascal source begin === OBLocation = class external 'org.bukkit' name 'Location' (JLObject, JLCloneable) public ... function clone(): OBLocation; overload; virtual; ... // <= other functions between function clone(): JLObject; overload; virtual; // throws java.lang.CloneNotSupportedException end; === Pascal source end === Is this indeed correct? Does the compiler (or the JVM) indeed call the correct function in the end (in this case org.bukkit.Location.clone)?

The Java language does not support overloading based on result type, just like FPC. The JVM bytecode specs do allow it though, which enabled Sun to allow overriding an inherited method with a method that returns a child type of the original result type.

They do this by automatically also generating a method with the original return type, which simply calls the newly added method (since the child type can be implicitly converted to the original type, this is no problem). That way, regardless of which method is called, the correct code is always executed. This is required for correct operation because if, in your example, you would assign the OBLocation instance to a JLObject variable and then call its clone method (assuming for a moment that clone would be public in JLObject), javacc would generate code to call the clone-variant that returns JLObject rather than OBLocation (since JLObject does not declare clone with an OBLocation result type).

The warning in this case should probably be demoted to a hint in case of external classes, because for simplicity reasons javapp does not check for each method whether it is overriding method in a parent class or not. That is already done in most cases, but not for this particular case, apparently. It's strange that the clone():JLObject method apparently does not get a "synthetic" attribute in the class file (otherwise javapp would skip it), because that's normal for compiler-generated routines.

Jonas

PS: There's currently a bug in the JVM compiler in that it also allows you to override functions with ones that have a different return type, but it doesn't automatically generate overridden methods using the original return type to redirect them to the new one.

Reply by email

Sven Barth
to Jonas Maebe
Jonas Maebe wrote 7 lines
On 28 Dec 2011, at 23:28, Sven Barth wrote: > 1) as it seems to be a rather usual practice in Java, would it be possible to disable the "Constructor should be public" warnings if the target cpu is the JVM? Yes.

This would be nice :)

Show quoted text 19 lines
> 2) in the code I converted the classes often seem to "reintroduce" methods that are available in parent classes or implemented interfaces with different result types without declaring the original method though. > > === Pascal source begin === > > OBLocation = class external 'org.bukkit' name 'Location' (JLObject, JLCloneable) > public > ... > function clone(): OBLocation; overload; virtual; > ... //<= other functions between > function clone(): JLObject; overload; virtual; // throws java.lang.CloneNotSupportedException > end; > > === Pascal source end === > > Is this indeed correct? Does the compiler (or the JVM) indeed call the correct function in the end (in this case org.bukkit.Location.clone)? The Java language does not support overloading based on result type, just like FPC. The JVM bytecode specs do allow it though, which enabled Sun to allow overriding an inherited method with a method that returns a child type of the original result type. They do this by automatically also generating a method with the original return type, which simply calls the newly added method (since the child type can be implicitly converted to the original type, this is no problem). That way, regardless of which method is called, the correct code is always executed. This is required for correct operation because if, in your example, you would assign the OBLocation instance to a JLObject variable and then call its clone method (assuming for a moment that clone would be public in JLObject), javacc would generate code to call the clone-variant that returns JLObject rather than OBLocation (since JLObject does not declare clone with an OBLocation result type).

Thank you for explaining this.

The warning in this case should probably be demoted to a hint in case of external classes, because for simplicity reasons javapp does not check for each method whether it is overriding method in a parent class or not. That is already done in most cases, but not for this particular case, apparently. It's strange that the clone():JLObject method apparently does not get a "synthetic" attribute in the class file (otherwise javapp would skip it), because that's normal for compiler-generated routines.

According to
http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc.html#80128 it should be rather easy to see whether a class file contains a synthetic method, right? So a "cat classfile | grep -i synthetic" should be sufficient? If so then there is indeed no such synthetic attribute used in that class...

PS: There's currently a bug in the JVM compiler in that it also allows you to override functions with ones that have a different return type, but it doesn't automatically generate overridden methods using the original return type to redirect them to the new one.

Thank you for the warning.

Regards,
Sven

Reply by email

Flávio Etrusco
to Jonas Maebe: Yes. The Java language does not support overloading based on result type, just like FPC.…
Jonas Maebe wrote 5 lines
On 28 Dec 2011, at 23:28, Sven Barth wrote: > 1) as it seems to be a rather usual practice in Java, would it be possible to disable the "Constructor should be public" warnings if the target cpu is the JVM? Yes.

BTW, is there anything you dislike about Java "constructor model"? ;-) (i.e. must call some inherited constrcutor, constructor can be - enforced - private, default public constructor if none declared, etc)

Best regards,
Flávio

Reply by email

Jonas Maebe
to Sven Barth: This would be nice :) Thank you for explaining this. According to…
Sven Barth wrote 9 lines
On 29.12.2011 13:49, Jonas Maebe wrote: > > On 28 Dec 2011, at 23:28, Sven Barth wrote: > >> 1) as it seems to be a rather usual practice in Java, would it be possible to disable the "Constructor should be public" warnings if the target cpu is the JVM? > > Yes. This would be nice :)

Actually, it should only be done for external classes. For classes defined in Pascal code, the compiler itself enforces the default FPC/Delphi behaviour whereby constructors from parent classes are automatically inherited (if it would not do that, you would have to manually redeclare every constructor that you wanted to reuse, because you cannot construct a Java class using a constructor defined in a parent class). As a result, every class will have at least one public constructor (a parameterless one), which is the original reason for the warning and the same on all targets.

You can of course always use the -vq/-vm command line parameters to manually disable that warning.

Jonas

Reply by email

Sven Barth
to Jonas Maebe
Jonas Maebe wrote 14 lines
On 29 Dec 2011, at 14:18, Sven Barth wrote: > On 29.12.2011 13:49, Jonas Maebe wrote: >> >> On 28 Dec 2011, at 23:28, Sven Barth wrote: >> >>> 1) as it seems to be a rather usual practice in Java, would it be possible to disable the "Constructor should be public" warnings if the target cpu is the JVM? >> >> Yes. > > This would be nice :) Actually, it should only be done for external classes. For classes defined in Pascal code, the compiler itself enforces the default FPC/Delphi behaviour whereby constructors from parent classes are automatically inherited (if it would not do that, you would have to manually redeclare every constructor that you wanted to reuse, because you cannot construct a Java class using a constructor defined in a parent class). As a result, every class will have at least one public constructor (a parameterless one), which is the original reason for the warning and the same on all targets.

For me it would be ok if this is for external classes only.

You can of course always use the -vq/-vm command line parameters to manually disable that warning.

This is of course always a possibility, but this is a case - in my opinion - where not the symptom, but the cause the should be healed. ;)

Regards,
Sven

Reply by email