eclipse-archived / ceylon-ide-eclipse

Eclipse Plugin for Ceylon
http://ceylon-lang.org/documentation/ide
Eclipse Public License 1.0
59 stars 28 forks source link

"Introduction to Ceylon modules" needs to declare the module as native (or somehow else handle the broken import) #1652

Open ePaul opened 8 years ago

ePaul commented 8 years ago

Wrong behavior I just installed Ceylon-IDE (1.2.0) on my work computer, and tried to go through the intros. Following "Introduction to Ceylon Modules" (which comes from ModulesIntro.xml) gives me this module.ceylon:

module org.zalando.ceylon_stups.helloWorld "1.0.0" {
    import ceylon.math "1.2.0";
}

The ceylon.math part is underlined red, due to a »Ceylon Module dependency Error«, with message »native import for cross-platform module (mark either the module or the import as native)«.

Expected behavior When following a tutorial, valid code should be produced.

Proposal It looks like the module needs to be annotated native("jvm").

There should also be some explanation why this is necessary (and what its meaning is).


Related Issue #4561 in main Ceylon project.

gavinking commented 8 years ago

Actually what we should do here is change it to use the new cross-platform ceylon.random when @jvasileff's work is merged.

ePaul commented 8 years ago

@gavinking Sounds good, I was not aware of that. Though I still think that also the native stuff should be explained somewhere.

lukehutch commented 8 years ago

Ran into the same issue going through the walkthrough. But even with the new cross-platform ceylon.random in place, this bug illustrates some other issues with the native imports that the IDE and the error messages don't help much with.

After you add native(jvm) to the module declaration, you get an error on random() in the following code, "Illlegal reference to native declaration random: declaration run is not native (mark it or the module native)":

import ceylon.math.float {
    random
}
"Run the module `dice`."
shared void run() {
    print("You rolled ``(random()*6).integer+1`` ``(random()*6).integer+1``"); 
}

I think what this means is that run() (or its module) needs to be marked native, so I added native("jvm") before shared void run(). The error on random() goes away, but now there's a new error on run(): "Shared native implementation must have a header: run".

At this point I have no idea what this means or how to fix it. I found the code in the Ceylon compiler source that generates the error, but it didn't help. I don't know what a header is yet, and haven't been able to find any documentation on this error or on using headers with native imports. I spent half an hour googling for various combinations of keywords, and trying different things, but to no avail. Not a great onboarding experience so far!

lukehutch commented 8 years ago

And the fix seems to be to have the following module declaration:

native("jvm") module dice "1.0.0" {
    native("jvm") import ceylon.math "1.2.0";
}

(I had only the following, after fixing the first problem):

module dice "1.0.0" {
    native("jvm") import ceylon.math "1.2.0";
}

So:

  1. You can't just declare individual methods that call native code as native? (Even though the compiler error suggests that as one of the two possible fixes...)
  2. It's possible to declare a non-native module with native imports, but you can't actually use those native imports unless the whole module is declared as native? If so, it seems like the compiler should give a warning or error on a non-native module with native imports.
ghost commented 8 years ago

@lukehutch you can only use native modules inside native declarations. However, you can have a pure Ceylon fallback to a native implementation, so your module doesn't need to be native as well... In fact, I think that if your module is native, adding the native annotation to its imports is not required, and it's even kinda redundant... I hope that clarify things... :-)

ghost commented 8 years ago

Also, I'd recommend avoiding fiddling with native stuff if you're just starting with Ceylon... The issue here is that there is code in the walkthrough that is wrong, and not about native things themselves... It's probably code that remained in the walkthrough from older versions where it worked...

ghost commented 8 years ago

Also, what the compiler is saying with "Shared native implementation must have a header: run" is that you should have a pure Ceylon fallback to that function. That's because your function is shared (which means that other modules should be able to call it), and because your module isn't native (other non-native modules should be able to import it and call any of its shared functions)...

gavinking commented 8 years ago

@lukehutch you have two options:

  1. mark the whole module native("jvm"), or
  2. create a native (header) function run() (just the signature), with native("jvm") and native("js") implementations.

The problem here is that @quintesse still has not documented the native functionality. Tako what is going on with that?

ghost commented 8 years ago

@gavinking oh, I see, so you can have a native function without a pure Ceylon implementation...I'd imagine you'd have to explicitly throw an error if you can't implement it in pure Ceylon... What happens if the function is called from a backend you don't support?

gavinking commented 8 years ago

oh, I see, so you can have a native function without a pure Ceylon implementation

Of course! We use that all over the place in the language module, and now even in the SDK.

I'd imagine you'd have to explicitly throw an error if you can't implement it in pure Ceylon

No, you just have an empty body, like you have with a formal method.

What happens if the function is called from a backend you don't support?

You have to provide a native implementation for all backends the module supports.

ghost commented 8 years ago

@gavinking

What happens if the function is called from a backend you don't support?