Sign in Join

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

Mailing lists / fpc-devel / 2011-08

FPC-JVM: Breaking up a cycle

8 messages · 2 people · –

Reply by email Subscribe to this list Your subscription

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

Sven Barth

Hello together and especially Jonas!

I have now ported most of the contents of the android namespace to Pascal. First I tried to put the subnamespaces into their own units, but that started to result in some nasty circles that involved parent classes and what not... now I have simply put the complete android namespace into one unit and at first I had quite a few order problems to solve, but now I have managed to get down to four errors and those are related to each other and are part of a circle problem.

The situation:

There is a class AVView, a class AVViewGroup and an interface AVViewManager. AVViewGroup extends AVView and implements AVViewGroup. Also it defines a nested class InnerLayoutParam.

So far all is ok, but now the problematic part:
AVView and AViewManager both contain a parameter and/or result value of type AVViewGroup.InnerLayoutParam.

Is there a way to solve this quite nasty circle?

Regards,
Sven

Reply by email

Jonas Maebe
to Sven Barth
Sven Barth wrote 6 lines
There is a class AVView, a class AVViewGroup and an interface AVViewManager. AVViewGroup extends AVView and implements AVViewGroup. Also it defines a nested class InnerLayoutParam. So far all is ok, but now the problematic part: AVView and AViewManager both contain a parameter and/or result value of type AVViewGroup.InnerLayoutParam. Is there a way to solve this quite nasty circle?

Not in a clean way. The only way you can do it is by removing AVViewGroup.InnerLayoutParam from the AVViewGroup class and declare it as an empty class up front (empty because I don't think it will be handled correctly if you add methods etc to it and try to call those later):

  AVViewGroup_InnerLayoutParam = class external 'Android.V_add_rest_of_package_name' name 'ViewGroup$Layoutparam' (parentclass,parentintf1,parentintf2, ...)
  end;

And then replace all references to AVViewGroup.InnerLayoutParam with references to AVViewGroup_InnerLayoutParam.

It's a limitation of the Pascal language compared to Java (no way to refer to inner classes before the parent class has been defined), and even if we would choose to lift it somehow (e.g. by allowing something like "AVViewGroup.InnerLayoutParam = class;" as a top level declaration) I'm not immediately sure how we to implement that efficiently in the compiler.

Jonas

Reply by email

Sven Barth
to Jonas Maebe
Jonas Maebe wrote 16 lines
On 27 Aug 2011, at 00:16, Sven Barth wrote: > There is a class AVView, a class AVViewGroup and an interface AVViewManager. AVViewGroup extends AVView and implements AVViewGroup. Also it defines a nested class InnerLayoutParam. > > So far all is ok, but now the problematic part: > AVView and AViewManager both contain a parameter and/or result value of type AVViewGroup.InnerLayoutParam. > > Is there a way to solve this quite nasty circle? Not in a clean way. The only way you can do it is by removing AVViewGroup.InnerLayoutParam from the AVViewGroup class and declare it as an empty class up front (empty because I don't think it will be handled correctly if you add methods etc to it and try to call those later): AVViewGroup_InnerLayoutParam = class external 'Android.V_add_rest_of_package_name' name 'ViewGroup$Layoutparam' (parentclass,parentintf1,parentintf2, ...) end; And then replace all references to AVViewGroup.InnerLayoutParam with references to AVViewGroup_InnerLayoutParam.

Ok, thank you. I'll play around with that

It's a limitation of the Pascal language compared to Java (no way to refer to inner classes before the parent class has been defined), and even if we would choose to lift it somehow (e.g. by allowing something like "AVViewGroup.InnerLayoutParam = class;" as a top level declaration) I'm not immediately sure how we to implement that efficiently in the compiler.

Well... as long as the "workaround" will work I'm rather happy :)

Regards,
Sven

Reply by email

Jonas Maebe
to Sven Barth: Hello together and especially Jonas! I have now ported most of the contents of the…
Sven Barth wrote
I have now ported most of the contents of the android namespace to Pascal. First I tried to put the subnamespaces into their own units, but that started to result in some nasty circles that involved parent classes and what not... now I have simply put the complete android namespace into one unit and at first I had quite a few order problems to solve

BTW: the javapp program normally solves the ordering problem for you. However, it can't do that if there are circular references... Normally, you'd solve those by specifying the classes whose removal results in breaking the circle(s) using the "-a" parameter of javapp (it will then turn those classes into an empty definition), but that only works for top-level classes.

Jonas

Reply by email

Sven Barth
to Jonas Maebe
Jonas Maebe wrote 6 lines
On 27 Aug 2011, at 00:16, Sven Barth wrote: > I have now ported most of the contents of the android namespace to Pascal. First I tried to put the subnamespaces into their own units, but that started to result in some nasty circles that involved parent classes and what not... now I have simply put the complete android namespace into one unit and at first I had quite a few order problems to solve BTW: the javapp program normally solves the ordering problem for you. However, it can't do that if there are circular references... Normally, you'd solve those by specifying the classes whose removal results in breaking the circle(s) using the "-a" parameter of javapp (it will then turn those classes into an empty definition), but that only works for top-level classes.

Besides the AVViewGroup problem there weren't any circles, but javapp failed to order the other classes correctly... it had reported messages for them though like "AVDontKnow is part of circle []" or so (I don't remember the message exactly anymore, but the brackets were empty, while they weren't for AVView, AVViewManager and AVViewGroup).

While we're at it: for one class (android.os.FileObserver, see here: http://developer.android.com/reference/android/os/FileObserver.html ) it generated the following:

=== source begin ===

   public
     procedure <init>_(para1: JLString); overload; virtual;
     procedure <init>_(para1: JLString; para2: jint); overload; virtual;

=== source end ===

These should be constructers, shouldn't they? Other constructors (even with parameters) were converted correctly.

Besides this javapp is a invaluable tool for Pascal developers :D

Regards,
Sven

Reply by email

Jonas Maebe
to Sven Barth
Sven Barth wrote 5 lines
On 27.08.2011 00:49, Jonas Maebe wrote: > > BTW: the javapp program normally solves the ordering problem for you. However, it can't do that if there are circular references... Normally, you'd solve those by specifying the classes whose removal results in breaking the circle(s) using the "-a" parameter of javapp (it will then turn those classes into an empty definition), but that only works for top-level classes. Besides the AVViewGroup problem there weren't any circles, but javapp failed to order the other classes correctly...

That's because the behaviour of the topological sort that's used to order them is probably undefined in the presence of cycles. Maybe it simply terminates when it encounters the first cycle to avoid getting stuck in an endless loop later.

Show quoted text 11 lines
While we're at it: for one class (android.os.FileObserver, see here: http://developer.android.com/reference/android/os/FileObserver.html ) it generated the following: === source begin === public procedure <init>_(para1: JLString); overload; virtual; procedure <init>_(para1: JLString; para2: jint); overload; virtual; === source end === These should be constructers, shouldn't they? Other constructors (even with parameters) were converted correctly.

What happens if you use "javap" to print that class rather than javapp? So javap -classpath android.jar android.os.FileObserver

Besides this javapp is a invaluable tool for Pascal developers :D

It was to be expected that it wouldn't work perfectly for everything immediately :)

Jonas

Reply by email

Sven Barth
to Jonas Maebe
Show quoted text 14 lines
> While we're at it: for one class (android.os.FileObserver, see here: http://developer.android.com/reference/android/os/FileObserver.html ) it generated the following: > > === source begin === > > public > procedure<init>_(para1: JLString); overload; virtual; > procedure<init>_(para1: JLString; para2: jint); overload; virtual; > > === source end === > > These should be constructers, shouldn't they? Other constructors (even with parameters) were converted correctly. What happens if you use "javap" to print that class rather than javapp? So javap -classpath android.jar android.os.FileObserver

Here it is:

=== output begin ===

Compiled from "FileObserver.java"
public abstract class android.os.FileObserver extends java.lang.Object{
     public static final int ACCESS;
     public static final int MODIFY;
     public static final int ATTRIB;
     public static final int CLOSE_WRITE;
     public static final int CLOSE_NOWRITE;
     public static final int OPEN;
     public static final int MOVED_FROM;
     public static final int MOVED_TO;
     public static final int CREATE;
     public static final int DELETE;
     public static final int DELETE_SELF;
     public static final int MOVE_SELF;
     public static final int ALL_EVENTS;
     public android.os.FileObserver(java.lang.String);
     public android.os.FileObserver(java.lang.String, int);
     protected void finalize();
     public void startWatching();
     public void stopWatching();
     public abstract void onEvent(int, java.lang.String);
}

=== output end ===

> Besides this javapp is a invaluable tool for Pascal developers :D It was to be expected that it wouldn't work perfectly for everything immediately :)

But it works good enough to convert most of the Android SDK without to big problems :)

Regards,
Sven

Reply by email

Jonas Maebe
to Sven Barth
Sven Barth wrote 26 lines
Here it is: === output begin === Compiled from "FileObserver.java" public abstract class android.os.FileObserver extends java.lang.Object{ public static final int ACCESS; public static final int MODIFY; public static final int ATTRIB; public static final int CLOSE_WRITE; public static final int CLOSE_NOWRITE; public static final int OPEN; public static final int MOVED_FROM; public static final int MOVED_TO; public static final int CREATE; public static final int DELETE; public static final int DELETE_SELF; public static final int MOVE_SELF; public static final int ALL_EVENTS; public android.os.FileObserver(java.lang.String); public android.os.FileObserver(java.lang.String, int); protected void finalize(); public void startWatching(); public void stopWatching(); public abstract void onEvent(int, java.lang.String); }

It's caused by the fact that javapp calls all constructors to "create". It then notices that the method name "create" conflicts with the constant CREATE, and tries to solve it by renaming the constructor to its original name + '_' (and setting the external name to the original name). Internally, the name of the constructor in class files is "<init>", so that gets changed into "<init>_" and as a result the filter afterwards to translate "<init>" to "create" isn't triggered anymore.

I can fix that, but then the constructor will still be called "Create_" rather than "Create" :/

Jonas

Reply by email