Hi Eric, That commonjs/require loading pattern is not bad [wrapping eval'ed code inside a function]. If your loaded scripts are (somewhat) well-behaved, it does solve the problem of global namespace pollution.
Yes, ScriptObjectMirrors are not uniformly treated like ScriptObject everywhere. But, I'm not sure how far we can fix that :( Is JSON handling (w.r.t ScriptObjectMirror) your main pain point? We *may* be able to address that. Thanks, -Sundar On 5/12/2016 11:10 PM, Eric Pederson wrote: > Hi Sundar: > > 1. I investigated loadWithNewGlobal because it looked promising for > this use case. Say you use loadWithNewGlobal to load a function. If > you call the loaded function and it returns an object or array the > caller gets a ScriptObjectMirror. The problems with a > ScriptObjectMirror "object" are: > > * Cannot call Object methods like keys or getOwnPropertyNames. You > get an exception: TypeError: cannot call undefined. To iterate > over the properties you must use a for in loop. > * Cannot convert ScriptObjectMirror to JSON using JSON.stringify. > It returns undefined. > > If the function loaded with loadWithNewGlobal returns an array then > things are better. Interestingly you can call most Array methods > (like forEach and map) on a ScriptObjectMirror "array". > But JSON.stringify also returns undefined. > > I did find one issue with an array returned by a loadWithNewGlobal > loaded function - calling sort with a comparator. For example, if the > loaded function returned testArray, a ScriptObjectMirror "array": > > *var **/sorted /*= */testArray/*.sort(*function*(a, b) { > > *return *a - b; }); > > > > throws an exception_: _TypeError: function(a, b) { return a - b; } is > not a function. > > > These were the same "mutant" issues that we also saw with JSObjects > returned by Java methods. > > > The hack that we are using now to load code without effecting the > global namespace is the same one discussed in this thread: > > http://thread.gmane.org/gmane.comp.java.openjdk.nashorn.devel/1722. > > > The code that we are using is copied/adapted from Vertx (thanks, Tim!): > > > function loadEval(path) { > > *var *dir = *new **/File/*(path).getParent(); > > *var *body = /readFile/(path); > > *var *moduleFunc = > > *"function(exports, module, require, __filename, > __dirname){" *+ body + *"**\n**}**\n**//# sourceURL=" *+ path; > > > *try {* > > *var *func = eval(moduleFunc); > > } *catch *(ex) { > > *if *(ex *instanceof **SyntaxError*) { > > /// WARNING! Large pile of Yak hair ahead! > / > > / /*var *ne = ex.nashornException; > > *var *cause = ne.cause; > > *var *msg = cause.message.replace(*"<eval>"*, file); > > *var *lineNumber = cause.*lineNumber;* > > console.log(*"ERROR: " *+ msg + *" in file " *+ file + *" > at line " *+ lineNumber); > } > > *throw *ex; > } > > *var *module = { *exports*: {} }; > > func(module.*exports*, module, require, path, dir); > > *return *module.*exports*; > > } > > > This seems like a hack to me - but I'm coming from the Java world so > this may be par for the course in Javascript-land :) Hack or no, it > is the best of both worlds: it does not change the global namespace, > yet the code that it returns lives in the global context, so if you > call a loaded function it will return a native object, not > a ScriptObjectMirror. > > > We'd like to have a built-in equivalent of this loadEvalfunction. It > doesn't need to use those specific arguments (export, module, etc), > but you must be able to pass arguments in to provide a context to the > loaded code. > > > Alternatively if you could make ScriptObjectMirrors 100% compatible > with native objects that would work too. Then we could use > loadWithNewGlobal. > > > 2. The problem that we are having with objects returned by Java > methods is the same as what I described above because the returned > JSObjects are seen as ScriptObjectMirrors by the calling Javascript > code. > > > What we are doing now is wrapping each Java object with a Javascript > proxy. When you call the proxy it calls the corresponding Java > method, then converts the returned ScriptObjectMirrorinto a native JS > object using a custom conversion function. > > > What would be nice for this use case is a standard function to convert > ScriptObjectMirrors to native JS objects (what I was > calling asJSONCompatible below). Or if ScriptObjectMirrors were 100% > compatible that would be even better - we could get rid of our JS > proxy objects. > > > I'm happy to file some enhancement requests. Though it seems like the > bug trackers are read-only to the general public though, how would I > get access? > > > Thanks, > > > > -- Eric > > On Thu, May 12, 2016 at 12:36 AM, Sundararajan Athijegannathan > <sundararajan.athijegannat...@oracle.com > <mailto:sundararajan.athijegannat...@oracle.com>> wrote: > > Hi, > > Thanks for your comments! > > Making comments on forthcoming JDK releases is hard :) Whatever I'm > saying now, may not happen - the usual disclaimer applies. > > No, we expect that only a subset of ES6 features will be > implemented for > Java 9. > > 1. On loading definitions without changing global namespace: you meant > current global namespace? loadWithNewGlobal creates a new global and > loads definitions into that. > > Would that be useful for you? or anything else? Which hack you're > referring to? Please file an enhancement with your requirements. > > 2. on JSON: Again, will you please provide a simple test case and/or > file an enhancement with requirements? > > Thanks, > -Sundar > > On 5/12/2016 12:56 AM, Eric Pederson wrote: > > I've been noticing the Java 9 ES6 features tweeted by > @sundararajan_a > > <https://twitter.com/sundararajan_a>. Looks awesome! Will > there be full > > ES6 support in Java 9? > > > > There are a couple of other things we would love to see in the > updated > > Nashorn: > > > > 1. We've been using the same hack that you recommended to Tim > Fox for > > loading functions without changing the global namespace - the > Avatar/js > > CommonJS/require hack. It would be great if this was supported > natively in > > Nashorn via a new loadXXX(). > > > > 2. It would be also be great to have the inverse of > asJSONCompatible for a) > > JSObjects returned by Java code and b) objects from other > scopes. Our name > > for ScriptObjectMirrors in Javascript code is "mutant objects": > they look > > like regular JS objects but they are missing most of their DNA, > and you > > don't realize until you get an exception or silent failure > somewhere down > > the call chain where it's difficult to figure out why :) > > > > Anyway, the upcoming stuff looks great! > > > > Thanks, > > > > -- Eric > >