Pro tip: Go straight for ECMAScript 5, don't waste your time on 3. With CL-JavaScript (http://marijnhaverbeke.nl/cl-javascript) we also thought 3 would be easier, but now we regret our decision:
- The ECMA5 document is (slightly) easier to read.
- Most 'extra' ECMA5 features can be added later, piecemeal, so initial development doesn't have to be more complicated.
- People will want ECMA5 eventually anyway.
- It is a waste of time to work through two ugly standards when one would have sufficed.
Awesome. Question: I was under the impression (perhaps mistakenly) that it would be impossible (or very hard) to statically compile a highly dynamic language like Javascript. Yes, No? Are there shortcuts Mug takes or disallowed coding styles?
How would Mug handle the following RuPyScript pseudocode:
for i in 1..10; eval "def function$i; print 'I'm $i'; end"; end
As al_james metioned, in order to emulate a dynamic language, you have to take a lowest-common-denominator approach. Thus all objects are of the type JSObject, which has functions for get() set() invoke() etc.-- basically a glorified HashMap+Runnable.
However, you don't need to wrap objects for arithmetic operations. At the moment Mug can determine the result of some types of expressions. If you're adding two doubles, it doesn't wrap the numbers before adding them. If you're calling (10).toString(), then it will autobox the number just as defined in the ECMAScript spec (the [[ToObject]] operation).
Deterction currently only works where types are explicit (a number literal will always be a number, etc.) The next step is to do type analysis on local variables, which will allow loops like for (var i = 0; i < 10; i++) { ... } to be compiled without wrapping primitives at all, greatly improving speed.
If you mean 'dynamically typed', then there's no particular problem - that's mainly a function of how you implement your calling protocols. It's much easier to write a dynamic compiler, actually, since you don't need to catch type errors at compile time.
If you mean 'supports eval', as your example seems to indicate, then you'll have to include either a compiler or interpreter in the language runtime - there's really no way around that. But it's not a big deal unless you're in some kind of embedded environment, and in that case you're probably not using a language that supports 'eval' anyway.
One of his strategies (from the README on Github) is "favoring static compilation rather than a runtime interpreter", so I suspect that `eval` is not included in Mug.
However, `apply` is included (cf. test/regression.js line 19). So your example pseudocode could probably be written like this:
for (var i = 1; i <= 10; i++) {
var f = function() {
print("I'm " + i.toString());
};
f();
}
Right. Technically Mug will conform to the ECMAScript 3 Compact Profile: http://www.ecma-international.org/publications/files/ECMA-ST... Which doesn't include eval() or the with(){} statement (both used infrequently enough that it's not worth the overhead).
A REPL would still be possible, however, it would require some work to maintain the current scope between input.
Much of the runtime has been developing by trying out existing code, then adding support gradually. Of course most of the code I tried out was ECMA3 compliant.
I expect to add in support for ECMAScript 5's Object extensions API (defineProperty, getters/setters) as Mug supports them internally, just as Mug already has a global JSON object. The features which could cause incompatibility with existing code is something I'd have to consider separately, so it depends when a majority of authors start writing ECMA5-compliant code (no function.callee, implicit this object bound to global, etc.)
As a follow up in case anyone is curious about the why behind this assertion, consider a line of code like this
eval("myObject."+functionName+"()")
Not only does it make it difficult to track down the calls to this method, it is now impossible to minify this chunk of code, something that is very commonly done in javascript. This is why javascript includes things like apply() and accessing members of an object in multiple ways (obj.attribute == obj['attribute'], for user-defined values of attribute).
I should imagine it wraps all values in its own flexible typed wrapper class and defines code for operations on them. This, of course, imposes quite an overhead.
Sometimes. The primitive types Mug can work with are `double`, `boolean`, `String`, and `JSObject`. This allows arithmetic operations and conditionals to be compiled without wrapping objects, and actual object invocations to be autoboxed as they are in JavaScript (like "a = 10" vs "a = new Number(10)")
The gaudy part is that there is only one type of function signature, basically "invoke(Object, Object, Object...)" which means Mug has to convert doubles to Doubles and booleans to Booleans across function calls... so it's somewhat of a tradeoff.
I'm guessing that Mug produces bytecode very different from that which you would normally want to run through GWT, and therefore might not be a very representative benchmark.
This is very exciting. Will be interesting to benchmark and see what the performance is like. It would be great if you dynamically compile JS to java classes at runtime (store procedures in JS etc).
Seriously? There's only 4 paragraphs total. How hard can it be? It's strange that it would make it hard to read. Typographic manuals usually suggest roughly 60 characters per line, favoring narrow columns over wide columns.
- The ECMA5 document is (slightly) easier to read.
- Most 'extra' ECMA5 features can be added later, piecemeal, so initial development doesn't have to be more complicated.
- People will want ECMA5 eventually anyway.
- It is a waste of time to work through two ugly standards when one would have sufficed.