Native feedback requested

73 views
Skip to first unread message

Tako Schotanus

unread,
Jul 7, 2015, 12:07:02 PM7/7/15
to ceylon-dev
This is mostly for Stephane and Tom, but anyone else who has any ideas is welcome to comment of course.

So Enrique came up with this test case:

    native shared class NativeHeader(variable Integer b, Integer c) {
        native shared String meth() => "Native header method ``nbm()``";
        native shared String attr => "Native header attribute ``nba``";
        native String nbm();
        native String nba;
    }

    native("jvm") shared class NativeHeader(variable Integer b, Integer c) {
        native("jvm") String nbm() => "``b++``:``c``";
        native("jvm") String nba => "``b++``:``c``";
    }

    native("js") shared class NativeHeader(variable Integer b, Integer c) {
        native("js") String nbm() => "``b++``,``c``";
        native("js") String nba => "``b++``,``c``";
    }

which is giving me problems on the JVM side because of the way I decided to implement this feature.

So first I'll explain how this is handled now. In the beginning I just ignored native headers (and I still do when they are methods or attributes) using them only as a template against which the implementations were checked (all signatures have to be exactly the same).

But as you can see a native header can have a default implementations for its native members (see "meth()" and "attr") which meant that they need to exist somewhere.

So what I decided to do was to create a hidden super class with a "$header" suffix which would look something like this:

    abstract public class NativeHeader$header {
        private long b;
        private final long c;
        public NativeHeader$header(long b$param, long c) {
            this.b = b$param;
            this.c = c;
        }
        public String meth() { return "Native header method " + nbm$priv(); }
        public String getAttr() { return "Native header attribute " + getNba$priv(); }
        abstract private String nbm$priv();
        abstract private String getNba$priv();
    }

and an implementation that would subclass it like this:

    public class NativeHeader extends NativeHeader$header {
        public NativeHeader$header(long b$param, long c) {
            super(b$param, c);
        }
        private String nbm$priv() { return "" + b++ + ":" + c; }
        private String getNba$priv() { return "" + b++ + ":" + c; }
    }

This works for simple cases but as you can see in the above code it won't work for anything slightly more complex because anything non-"shared" is always made "private" in the generated Java code.

So to make this work I'd need to remove all the "private" modifiers in the header and make sure I skip anything in the subclass that was already defined in the header.

The problem I see with this is that the generated class would be quite a bit different from what we normally generate and I just can't really foresee the problems this might cause in more complex cases.

So I thought of a different way to go about this problem and that is to not generate this special hidden header class but to generate just a single class using basically a merge of the header and its implementation.

We can do that because right now the header and its implementations must be in the same source file because I couldn't figure out the class-loading requirements for incremental compilation.

The problem I see with that particular solution is that the requirement for header and implementation to be in the same source file would be fixed forever, there would be no way to ever do incremental compilation (because the header would not really exist except in code).

So I hope this makes somewhat sense to you guys and you have some opinion on this you'd like to share.

-Tako

Tom Bentley

unread,
Jul 7, 2015, 3:27:01 PM7/7/15
to ceylon-dev
I agree there could be plenty of nasty corner cases in having two classes instead of one (`this` and `super` being obvious candidates for trouble), and I think the "merged" approach would be better, since that's what I'm doing in my head when I look at this kind of code. The same-source file restriction doesn't seem to be especially onerous. Sure, in an ideal world there wouldn't be that restriction, but I can't see how it would prevent us doing something which would otherwise be possible.

--
You received this message because you are subscribed to the Google Groups "ceylon-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ceylon-dev+...@googlegroups.com.
To post to this group, send email to ceylo...@googlegroups.com.
Visit this group at http://groups.google.com/group/ceylon-dev.
To view this discussion on the web visit https://groups.google.com/d/msgid/ceylon-dev/CAOJRyvpZU6%3Dgd30sv2dmQXZeJAweJ93q1ngdXXxVjCjJTtbN3Q%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.

Gavin King

unread,
Jul 7, 2015, 3:32:39 PM7/7/15
to ceylo...@googlegroups.com
It sounds reasonable to me.

Sent from my iPhone
--

Tako Schotanus

unread,
Jul 7, 2015, 3:34:32 PM7/7/15
to ceylon-dev
Good points Tom, thanks.

Do you see any possible problems related to the ordering of members in such a merged class/object?
I mean there are several ways I can think of that I could go about adding both the header and implementation members but none that would be strictly correct.
But ordering of members should not cause any problems, right?



-Tako

Tom Bentley

unread,
Jul 7, 2015, 3:36:49 PM7/7/15
to ceylon-dev
None that spring to mind, but I'm rubbish at that kind of forward thinking.

Lucas Werkmeister

unread,
Jul 7, 2015, 3:38:03 PM7/7/15
to ceylo...@googlegroups.com
Are both the header and the implementation allowed to include initialization logic (if there are no constructors)? If so, what runs first?

Tako Schotanus

unread,
Jul 7, 2015, 5:19:18 PM7/7/15
to ceylon-dev
I have no idea what would be the rules for such a case Lucas.
Right now I'm ignoring any such possibility and treat the header class more as an interface than a real class.
But if anyone can come up with something that makes sense I'm all ears.


-Tako

Stephane Epardaud

unread,
Jul 7, 2015, 5:22:14 PM7/7/15
to ceylon-dev
Having two classes also means you can never have a native class that extends another class, right? IMO the native header sounds more like an interface impl class in that it can contain code that we delegate to, but it sits outside the inheritance tree.


For more options, visit https://groups.google.com/d/optout.



--
Stéphane Épardaud

Lucas Werkmeister

unread,
Jul 7, 2015, 5:24:25 PM7/7/15
to ceylo...@googlegroups.com
The more I think about it, the more I agree that this should not be supported. It should be an error “native class initializer section must be empty”.

Tako Schotanus

unread,
Jul 7, 2015, 5:41:11 PM7/7/15
to ceylon-dev

On Tue, Jul 7, 2015 at 11:22 PM, Stephane Epardaud <stephane...@gmail.com> wrote:
Having two classes also means you can never have a native class that extends another class, right?

Well no, right now if you have something like:

    shared class A() {}
    native shared class B() extends A() {}

what will get generated is:

    public class A {}
    public class B$header extends A {}
    public class B extends B$header {}

but to make that work properly for non-shared members/parameters is quite some work (making them all "protected" instead of "private" for example) and god knows what kind of other problems are lurking around the corner.
The "merge" is easier to reason about (not sure yet how easy it will be to implement, using two source classes to generate one Java class).

-Tako

Tako Schotanus

unread,
Jul 9, 2015, 8:01:58 AM7/9/15
to ceylon-dev
Ok, I just pushed the new implementation of native classes and objects that doesn't use a separate `$header` class and inheritance anymore.

Everything seems to work fine and Enrique's tests in the language module now actually pass.

Please let me know if you find any problems with this new implementation.


-Tako

David Festal

unread,
Jul 13, 2015, 6:15:52 AM7/13/15
to ceylo...@googlegroups.com
I'm working on the IDE support of the new implementation.
> --
> You received this message because you are subscribed to the Google
> Groups "ceylon-dev" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to ceylon-dev+...@googlegroups.com.
> To post to this group, send email to ceylo...@googlegroups.com.
> Visit this group at http://groups.google.com/group/ceylon-dev.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/ceylon-dev/CAOJRyvqPJj46Mw36Bpk3CBt7sHFTgzK%3DnpJW6xzYCP6WUC6RyA%40mail.gmail.com.

David Festal

unread,
Jul 17, 2015, 5:11:15 AM7/17/15
to ceylo...@googlegroups.com
I've finished implementing the IDE support (incremental build and
navigation).

This seems to work quite well now, even :
- when the JVM native implementation is written in Java and both Java
and Javascript backends are enabled,
- for binary .CAR archives for which the native header or the alternate
JS implementation are found inside the corresponding source archive.

Please report if you find anything that should be fixed or further
enhanced.

David.

Le jeudi 09 juillet 2015 à 14:01 +0200, Tako Schotanus a écrit :
> --
> You received this message because you are subscribed to the Google
> Groups "ceylon-dev" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to ceylon-dev+...@googlegroups.com.
> To post to this group, send email to ceylo...@googlegroups.com.
> Visit this group at http://groups.google.com/group/ceylon-dev.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/ceylon-dev/CAOJRyvqPJj46Mw36Bpk3CBt7sHFTgzK%3DnpJW6xzYCP6WUC6RyA%40mail.gmail.com.

Tako Schotanus

unread,
Jul 17, 2015, 5:14:09 AM7/17/15
to ceylon-dev
Thanks David!


-Tako

Reply all
Reply to author
Forward
0 new messages