Open ikasiuk opened 12 years ago
Surely this is for M5?
yes
So I was thinking about top-level methods, especially for interop, and I thought that Dynamic could have an optional String in its initializer; any string passed there would be used instead of the regular object constructor, like this:
Object x = Dynamic(); //generates var x$blabla = {};
Callable<Dynamic,String> require = Dynamic("require"); //generates var require$blabla = require;
Callable<Dynamic,Dynamic> jquery = Dynamic("$"); //generates var jquery$blabla = $;
Dynamic elems = Dynamic("$('span#css')"); //generates var elems$blabla = $('span#css');
Of course this would open the door for invalid code generation which would only be detected at runtime, if invalid js code is put inside the Dynamic (such as an unclosed quote, parens, etc). Maybe the compiler can warn if it detects something that looks like invalid code inside a Dynamic call, and anyway this could solve the interop problem. WDYT @gavinking ?
Dunno, this sounds very hacky to me. Also remember that Dynamic
might be used by the Java backend in the future.
@chochos I think a better way would be a toplevel object named dynamic
of type Dynamic
, so you would write:
Callable<Dynamic,String> require = dynamic.require;
I don't think we should be sticking JavaScript code in strings.
However, I'm beginning to view Dynamic
itself as a rather inelegant solution, and I'm looking for other options. I think it would be better to have a specific syntax to suppress typechecking rather than a special Dynamic
type. One option would be to add operators for "reflective" member access:
~require(something).~someFunction()
Along with an operator to force assignability of Anything
to an arbitrary type:
Integer x = ~require(something).~someFunction()! + 1;
But really code with a bunch of ~
s and !
s is just not going to like like either Ceylon or JavaScript, it's just going to look awful. So I think a better answer would be a dynamic
block or dynamic
annotation:
Integer x;
dynamic {
x = require(something).someFunction() + 1;
}
The type of require()
and someFunction()
would be Anything
. The type of require(something).someFunction() + 1
would also be Anything
.
Well that's a bit how the nativejs
annotation works, you put it on a toplevel class or method and the JS compiler will generate normal JS accessors, so no Ceylon-specific name mangling at all. In the same manner we could have an annotation that suspends all typechecking on members of that type.
I still think it's a pretty heavy-handed solution that people in general should try to reserve for those cases where no other solution will do (for example dynamic objects that could have a different set of members depending on circumstances).
@quintesse Huh? What you just typed didn't make any sense.
How do you propose to let the typechecker know that it shouldn't produce an exception when I reference a member it doesn't know about, or try to apply an operator to something whose type it doesn't know?
@quintesse The nativejs
annotation is useful when you want to make typesafe interop, such as the browser
module you wrote for the web IDE; this dynamic
block allows you to disable type safety (and use undeclared stuff), so this would allow you to use for example the require
function in js, or call jquery stuff (still don't know how though, since the jquery function name is just $
), etc.
Moving to M6
Moving to 1.0
Moving to 1.1
We currently have JS interop for the browser DOM objects in ceylon-web-ide-backend. This works by defining a Ceylon version of the types' interfaces with annotation
nativejs
and implementing a JS module which makes these JS types available as Ceylon types. The compiler has special treatment for types withnativejs
annotation so that it can access them in the correct way.We should make this principle applicable to any native JS class. It should be possible to let the compiler automatically generate the JS glue code from the Ceylon type definitions. So to use a native JS class from Ceylon you would describe the interface of that class as a Ceylon type and annotate it
nativejs
. The compiler would then automatically generate the necessary glue code from that Ceylon file, enabling you to use the native JS class as if it was a Ceylon class.We will probably have to implement special handling for some identifier names to avoid collisions of native JS members with Ceylon members. Such special handling could also enable us for instance to merge ceylon.language.String with the builtin JS String class.